original files of m241
This commit is contained in:
@@ -0,0 +1,442 @@
|
||||
# Makefile - top level makefile for target/src to build runtime libraries
|
||||
#
|
||||
# Copyright (c) 1996-2012 Wind River Systems, Inc.
|
||||
#
|
||||
# The right to copy, distribute, modify or otherwise make use
|
||||
# of this software may be licensed only pursuant to the terms
|
||||
# of an applicable Wind River license agreement.
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 04o,07dec12,jpb Updated Makefile to build mils dir if its VSB is
|
||||
# configured.
|
||||
# 04n,29aug12,pfl renamed milsvdk to mils
|
||||
# 04m,13dec11,kab Cleanup for MILS release
|
||||
# 04l,16jun11,kab Added MILS
|
||||
# 04k,17dec10,pch CQ:WIND00244631: build ostool/shell/shellFuncBind
|
||||
# for small footprint
|
||||
# 04j,23sep10,d_c Integrate src/vendor with target VSB
|
||||
# 04i,01sep10,swg VxMP should not be built for LP64,
|
||||
# current VxMP doesn't support LP64
|
||||
# 04h,19jul10,mze moving VENDOR_DEFAULT logic
|
||||
# 04g,17feb10,pch small footprint
|
||||
# 04f,11jun10,mze include defs.library before the make. fragments
|
||||
# 04e,10mar10,gvm temporarily working around problem building tests with icc
|
||||
# 04d,05mar10,flu Modified the code for diab compilation (CQ:WIND00146073)
|
||||
# 04c,12aug09,mze change build of tags dir to always build first
|
||||
# 04b,20jul09,pee adding tags directory
|
||||
# 05a,20oct08,to add wrhv to COMMON_SUBDIRS
|
||||
# 04z,04jun09,pee add interface directory support for DUAL_BUILD=false
|
||||
# 04y,26may09,pee interface directory should only build for main compiler and
|
||||
# not for both.
|
||||
# 04x,19mar09,pee adding interface subdirctory
|
||||
# 04w,24jul08,dtr Remove wrload from the build.
|
||||
# 04v,04jul08,c_c merge from VXWORKS_ITER14_2008070401 label.
|
||||
# 04u,30jun08,ebh Add MIPC to list of directories
|
||||
# 04t,16may08,tpw Add 'analysis' subdir for /vobs/rtca target side content
|
||||
# 04s,05may08,ebh Add in wrload for building (ignored if code is not installed)
|
||||
# 04r,21apr08,kkz Fixing VENDOR_DEFAULT for gnu
|
||||
# 04q,15apr08,mcm Set GNU as default for all IA32.
|
||||
# 04p,26feb08,scm Set GNU as default for Pentium.
|
||||
# 04o,14oct07,mdk fix merge problem
|
||||
# 04n,11oct07,kk move back demo to DUAL_SUBDIRS
|
||||
# 04m,09oct07,mmi fix WIND00107245 move demo to COMMON_SUBDIR, remove
|
||||
# duplicate boot
|
||||
# 04l,20jul07,kch Remove pfw from COMMON_SUBDIRS.
|
||||
# 04k,23jun07,tkf Add wrn to COMMON_BASIC_SUBDIRS.
|
||||
# 04j,19jun07,vik included rule for vxbUsrCmdLine.c build
|
||||
# 04i,28jun07,tat removing cci-light
|
||||
# 04h,03may07,pch automate -basic build step
|
||||
# 04g,18apr07,ebh Add dshm builds
|
||||
# 04f,12apr07,pes Re-enable MIPS dual builds.
|
||||
# 04e,22mar07,pes Temporarily disable dual (gnu) build mechanism for MIPS.
|
||||
# 04d,17mar07,kkz Correcting merge error
|
||||
# 04c,05mar07,jrp Remove usb2 subdirectory
|
||||
# 04b,12jan07,tcr remove wv build
|
||||
# 04a,11dec06,mmi re-enable tipc
|
||||
# 03z,17nov06,bha Reabase to VXWORKS_2006_FALL_FRZ20
|
||||
# 03y,23sep06,tat adding cci-light
|
||||
# 03x,05sep06,lei temporarily disable tipc for SMP build.
|
||||
# 03w,26aug06,tkf Remove PPP from COMMON_SUBDIRS.
|
||||
# 03v,04aug06,jmt Add boot directory
|
||||
# 03u,12jul06,??? add ipnet to COMMON_SUBDIRS
|
||||
# 03t,30mar06,pes Add 'boot' to COMMON_SUBDIRS.
|
||||
# 03s,31jan06,mdk add ssi to COMMON_SUBDIRS
|
||||
# 03r,11jan06,yvp LOCAL_RCLEAN now cleans out all scgen derived files.
|
||||
# 03q,07nov05,mdo Add hwif
|
||||
# 03p,25aug05,ebh Eliminate reference to vxFusion
|
||||
# 03o,22jun05,pee Filter SUBDIRS to only include installed dirs (SPR #109230)
|
||||
# 03n,03jun05,dbt Removed wdb & hwdb directories.
|
||||
# 03m,27may05,jmp added debug directory.
|
||||
# 03l,29mar05,mem Unstitch unused MSP components, cleanup.
|
||||
# 03k,21feb05,ebh update manually (zippy merge was not running)
|
||||
# 03j,15feb05,als Added support for TIPC
|
||||
# 03i,18jan04,jmp added vxsim to DOCSUBDIRS (SPR #105749).
|
||||
# 03h,01sep04,jmp modified to only add vxsim to COMMON_SUBDIRS for simulator
|
||||
# arches (SPR #101208).
|
||||
# 03g,03aug04,edc Reverting changes for the test directory (SPR #98483).
|
||||
# 03f,22jun04,jyo Fixing SPR #98483.
|
||||
# 03e,09jun04,jyo SPR #98078: Removing the build of security
|
||||
# 03d,28may04,p_r add dsi to directory list
|
||||
# 03c,14may04,yvp Defined LOCAL_RCLEAN to cleanup SCGEN_DERIVED_FILES
|
||||
# 03b,07may04,h_k fixed the comments for PPC and SH default compiler.
|
||||
# 03a,05mar04,dat adding offset dir
|
||||
# 02z,22jan04,dbt Added support for GNU compiler on Solaris VxSim.
|
||||
# 02y,12jan04,bjl added DOCSUBDIRS.
|
||||
# 02x,10dec03,h_k Change default SH compiler to diab.
|
||||
# 02w,05dec03,dbt Added DIAB support for Linux & Windows VxSim.
|
||||
# 02v,03dec03,rp added ppp and pfw
|
||||
# 02u,13nov03,c_c Removed CPU variant definitions.
|
||||
# Removed WTX from build.
|
||||
# 02t,18nov03,zmm Change default Pentium compiler to diab.
|
||||
# 02r,21oct03,jb Enabling build of cache aim
|
||||
# 02q,27sep03,rp removing netwrs netinet bpf rip dhcp
|
||||
# 02p,19aug03,pch Change PPC VENDOR_DEFAULT to diab
|
||||
# 02o,24jul03,jeg added vxsim directory
|
||||
# 02n,09jul03,tam removed vxvmi directory
|
||||
# 02m,19jun03,dbt Build Solaris VxSim with DIAB compiler.
|
||||
# 02l,07may03,pch Add CPU_VARIANT definition for PPC
|
||||
# 02k,16apr03,pch Add hwdb subdirectory for PPC32
|
||||
# 02j,27jan03,zmm Add tx79xx processor family.
|
||||
# 02i,17jan03,agf add support for malta5kf
|
||||
# 02h,14nov02,jmt Add RM9000 processor family
|
||||
# 02g,26jun02,pes Remove MIPS32 builds from bcm125x
|
||||
# CPU_VARIANT_CPU_TOOL_LIST_bcm125x.
|
||||
# 02f,08may02,pes Change MIPS r3xxx CPU_VARIANT designation to rc3000
|
||||
# 02e,23apr02,pes Add support for rc4xxx, rc5xxx, rm52xx, rm57xx, tx49xx and
|
||||
# vr50xx processor families.
|
||||
# 02d,14mar02,t_m move the rule for man after the include so the default rule
|
||||
# is still Default
|
||||
# 02c,07mar02,pch Add arch/Makefile dependency for "man" target to fix cpuGen
|
||||
# fallout - SPR 73999
|
||||
# 02b,27feb02,pes Adjust per-cpu-family Library archive selections
|
||||
# 02a,11jan02,pes Insert macro definitions for MIPS repackaged libarch.a
|
||||
# libraries
|
||||
# 01z,12dec01,tam made CPU variant builds automatic; updated comments
|
||||
# 01y,12dec01,mem Fix specialization test for MIPS.
|
||||
# 01x,07dec01,tam Added CPU variant support
|
||||
# 01w,27nov01,jmp Changed to expect simpc instead of SIMNT for VX_CPU_FAMILY.
|
||||
# 01v,20nov01,tam move demo to dual build
|
||||
# 01u,16nov01,mil Changed to expect ppc instead of PPC for VX_CPU_FAMILY.
|
||||
# 01t,12nov01,tam added dual build support
|
||||
# 01s,07nov01,tam added vxvmi directory
|
||||
# 01r,31oct01,mas added vxmp subdirectory
|
||||
# 01q,30oct01,sn pushed gnu under new tool directory
|
||||
# 01p,29oct01,dbs re-instate vxcom and vxdcom
|
||||
# 01o,18oct01,dbs temporarily remove vxcom and vxdcom from build
|
||||
# 01n,11oct01,tpr Removed VxWorks 5.5 unsupported directories
|
||||
# 01m,04oct01,nel Add VxDCOM to build.
|
||||
# 01l,27apr01,mem Added vxFusion, zinc, missing dirs, remove ospf, wweb merge
|
||||
# 01k,07dec00,af add cplus and gnu back to default build list.
|
||||
# 01j,06nov00,sn add target for just building C++
|
||||
# 01i,09oct00,sn but do build everything on tor2_x-fred-toolchain
|
||||
# 01h,09oct00,sn don't build C++
|
||||
# 01g,11dec98,j_w define CLEANLIBS -- for removing lib$(CPU)$(TOOL)*.a
|
||||
# 01f,22may98,ms removed SUBDIRS hack
|
||||
# 01e,29apr98,dbt removed rdb directory
|
||||
# 01d,05nov97,kkk added rip, dhcp directory
|
||||
# 01c,28oct97,kkk added ospf directory
|
||||
# 01b,15nov96,jag added snmpv1 directory
|
||||
# 01a,17jun96,yp written
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules to select subdirectories that contain
|
||||
# sources for building the VxWorks runtime archive and builds them.
|
||||
#
|
||||
# Some architecures support only one toolchain family (either GNU or DIAB).
|
||||
# The toolchain supported is defined by VENDOR_DEFAULT below.
|
||||
# For instance to build the source tree for the solaris simulator which supports
|
||||
# only the GNU toolchain, you should issue the following commands:
|
||||
# > cd $WIND_BASE/target/src
|
||||
# > make CPU=SIMSPARCSOLARIS TOOL=gnu
|
||||
#
|
||||
# Other architecures support both toolchain families (GNU and DIAB).
|
||||
# However most of the VxWorks source code under $(WIND_BASE)/target/src/
|
||||
# is compiled with only one toolchain family (either GNU or DIAB). This
|
||||
# default toolchain is defined again by VENDOR_DEFAULT. Nevertheless part of
|
||||
# the VxWorks source tree must still be built with the secondary toolchain
|
||||
# family. This dual build is accomplished in two passes.
|
||||
#
|
||||
# For instance to build the source tree for CPU=PPC604 which supports both
|
||||
# GNU and DIAB, the following commands must be issued:
|
||||
# > cd $WIND_BASE/target/src
|
||||
# > make CPU=PPC604 TOOL=diab
|
||||
# > make CPU=PPC604 TOOL=gnu
|
||||
#
|
||||
#
|
||||
#
|
||||
# FOR TESTING PURPOSES
|
||||
# If a dual build of the source tree should not be performed for a CPU type
|
||||
# which by default supports both toolchain families, the value of DUAL_BUILD
|
||||
# must be overwritten on the command line.
|
||||
# For instance to build successfuly the entire source tree for CPU=PPC604 with
|
||||
# the DIAB toolchain despite it is not the default toolchain for this
|
||||
# architecture, issue the following commands:
|
||||
# > cd $WIND_BASE/target/src
|
||||
# > make CPU=PPC604 TOOL=diab DUAL_BUILD=false
|
||||
#
|
||||
# You may need to build the entire source tree with both toolchain families
|
||||
# (GNU and DIAB). Every source file must be compiled with both toolchains
|
||||
# and the resulting objects stored in a different locations. As above
|
||||
# DUAL_BUILD must be set to false and in addition the COMMON_DIR variable
|
||||
# must be overwritten and set to false:
|
||||
# > cd $WIND_BASE/target/src
|
||||
# > make CPU=PPC604 TOOL=diab DUAL_BUILD=false COMMON_DIR=false
|
||||
# > make CPU=PPC604 TOOL=gnu DUAL_BUILD=false COMMON_DIR=false
|
||||
#
|
||||
# INTERNAL
|
||||
# The REAME.txt file under $(WIND_BASE)/target/src/ should be updated whenever
|
||||
# this file is modified, if appropriate.
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
|
||||
# remove lib$(CPU)$(TOOL)*.a if make rclean is done at target/src level
|
||||
CLEANLIBS = YES
|
||||
|
||||
# get _WRS_CONFIG_xxx settings so they can be used in setting xxx_SUBDIRS
|
||||
include $(TGT_DIR)/h/make/defs.default
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
-include $(VSB_MAKE_CONFIG_FILE)
|
||||
|
||||
# IMPORTANT:
|
||||
#
|
||||
# New directories under $WIND_BASE/src must be added to one of the following
|
||||
# list, and only one:
|
||||
#
|
||||
# SKIP_SUBDIRS: directory(ies) not being compiled
|
||||
# COMMON_SUBDIRS: directories compiled with the default compiler
|
||||
# only (cf value of VENDOR_DEFAULT)
|
||||
# DUAL_SUBDIRS: directories compiled with each toolchain.
|
||||
# NOTE: any directory including C++ files must be
|
||||
# added to this list.
|
||||
# GNU_SUBDIRS: directories compiled with GNU only
|
||||
# DIAB_SUBDIRS: directories compiled with DIAB only
|
||||
|
||||
# Directories listed in COMMON_SUBDIRS should also be listed in
|
||||
# COMMON_BASIC_SUBDIRS if they need to be built both with and
|
||||
# without OPT=-basic
|
||||
|
||||
SKIP_SUBDIRS = zlib usb2
|
||||
|
||||
ifdef _WRS_CONFIG_MEM_ALLOT
|
||||
# Skip subdirectories whose contents would require memory management
|
||||
SKIP_SUBDIRS += analysis boot debug demo fs ipnet posix rpc ssi \
|
||||
tffs tipc usb vxmp vxsim vxvmi wrn
|
||||
endif
|
||||
# Skip vxmp if define _WRS_CONFIG_LP64, current VxMP doesn't support LP64
|
||||
ifdef _WRS_CONFIG_LP64
|
||||
SKIP_SUBDIRS += vxmp
|
||||
endif
|
||||
|
||||
# interface directory. Must be built first
|
||||
INTERFACE_SUBDIR = interface
|
||||
|
||||
# directories optionally installed
|
||||
|
||||
OPTIONAL_COMMON_SUBDIRS = security
|
||||
|
||||
COMMON_SUBDIRS = arch aim drv event hwif libc \
|
||||
math multios_ipc offset os ostool \
|
||||
usr util wind wrhv \
|
||||
$(wildcard $(OPTIONAL_COMMON_SUBDIRS))
|
||||
ifndef _WRS_CONFIG_MEM_ALLOT
|
||||
# Add these if not skipped above
|
||||
COMMON_SUBDIRS += boot debug dshm dsi fs posix rpc tffs tipc usb \
|
||||
wrn ssi ipnet
|
||||
# VxMP should not be built for LP64, current VxMP doesn't support LP64
|
||||
ifndef _WRS_CONFIG_LP64
|
||||
COMMON_SUBDIRS += vxmp
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef _WRS_CONFIG_MILS_VBI
|
||||
COMMON_SUBDIRS += mils
|
||||
endif
|
||||
|
||||
COMMON_BASIC_SUBDIRS = ipnet wrn
|
||||
|
||||
DUAL_SUBDIRS = vendor tags cplus tool test
|
||||
# - other C++ based code to be added
|
||||
# here
|
||||
# - other source directories not ported
|
||||
# to new archive directory hierarchy to
|
||||
# be added here too.
|
||||
|
||||
ifndef _WRS_CONFIG_MEM_ALLOT
|
||||
# Add demo if not skipped above
|
||||
DUAL_SUBDIRS += demo
|
||||
endif
|
||||
|
||||
GNU_SUBDIRS =
|
||||
|
||||
DIAB_SUBDIRS =
|
||||
|
||||
VXSIM_SUBDIRS = vxsim
|
||||
|
||||
|
||||
include $(TGT_DIR)/h/tool/$(TOOL_FAMILY)/make.$(CPU)$(TOOL)
|
||||
|
||||
## Architectures default toolchain and dual build status
|
||||
#
|
||||
# VENDOR_DEFAULT now defined in target/h/make/defs.default included above here.
|
||||
|
||||
#
|
||||
# ARM: DIAB & GNU (DIAB as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),arm)
|
||||
|
||||
# ARMV7-M: supports only DIAB
|
||||
|
||||
ifneq ($(CPU),ARMARCH7M)
|
||||
DUAL_BUILD = true
|
||||
else
|
||||
DUAL_BUILD = false
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# COLDFIRE: supports only DIAB
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),cf)
|
||||
DUAL_BUILD = false
|
||||
endif
|
||||
|
||||
#
|
||||
# MC68K: supports only GNU
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),68k)
|
||||
DUAL_BUILD = false
|
||||
endif
|
||||
|
||||
#
|
||||
# MIPS: DIAB & GNU (DIAB as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),mips)
|
||||
DUAL_BUILD = true
|
||||
endif
|
||||
|
||||
#
|
||||
# PENTIUM: DIAB & GNU (GNU as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),pentium)
|
||||
DUAL_BUILD = true
|
||||
endif
|
||||
|
||||
#
|
||||
# PPC: GNU & DIAB (DIAB as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),ppc)
|
||||
DUAL_BUILD = true
|
||||
endif
|
||||
|
||||
#
|
||||
# SH (Renesas): GNU & DIAB (DIAB as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),sh)
|
||||
DUAL_BUILD = true
|
||||
endif
|
||||
|
||||
#
|
||||
# SIMLINUX: supports GNU & DIAB (GNU as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),simlinux)
|
||||
DUAL_BUILD = true
|
||||
COMMON_SUBDIRS += $(VXSIM_SUBDIRS)
|
||||
endif
|
||||
|
||||
#
|
||||
# SIMNT: supports GNU & DIAB (GNU as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),simpc)
|
||||
DUAL_BUILD = true
|
||||
COMMON_SUBDIRS += $(VXSIM_SUBDIRS)
|
||||
endif
|
||||
|
||||
#
|
||||
# SIMSOLARIS: supports GNU & DIAB (DIAB as default)
|
||||
#
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),simso)
|
||||
DUAL_BUILD = true
|
||||
COMMON_SUBDIRS += $(VXSIM_SUBDIRS)
|
||||
endif
|
||||
|
||||
#
|
||||
# Analysis source is built with gnu for all target architectures except
|
||||
# coldfire.
|
||||
#
|
||||
|
||||
ifndef _WRS_CONFIG_MEM_ALLOT
|
||||
# Add analysis if not skipped above
|
||||
ifeq ($(VX_CPU_FAMILY),cf)
|
||||
DIAB_SUBDIRS += analysis
|
||||
else
|
||||
DUAL_SUBDIRS += analysis
|
||||
endif
|
||||
endif
|
||||
|
||||
# defaults for DUAL_BUILD
|
||||
|
||||
ifeq ($(DUAL_BUILD),)
|
||||
DUAL_BUILD = false
|
||||
endif
|
||||
|
||||
|
||||
|
||||
# Select the toolchain specific directories
|
||||
|
||||
ifeq ($(TOOL), $(TOOL_GNU))
|
||||
TOOL_DIRS = $(GNU_SUBDIRS)
|
||||
endif
|
||||
ifeq ($(TOOL), $(TOOL_DIAB))
|
||||
TOOL_DIRS = $(DIAB_SUBDIRS)
|
||||
endif
|
||||
|
||||
|
||||
## Compute list of directories to build:
|
||||
#
|
||||
# Set SUBDIRS according to DUAL_BUILD and VENDOR_DEFAULT
|
||||
# filter list to existing directories only
|
||||
|
||||
ifeq ($(DUAL_BUILD),false)
|
||||
__SUBDIRS = $(INTERFACE_SUBDIR) $(COMMON_SUBDIRS) $(DUAL_SUBDIRS) $(TOOL_DIRS)
|
||||
else
|
||||
ifeq ($(DUAL_BUILD),true) # just to make sure
|
||||
ifeq ($(TOOL_VENDOR),$(VENDOR_DEFAULT))
|
||||
__SUBDIRS = $(INTERFACE_SUBDIR) $(COMMON_SUBDIRS) $(DUAL_SUBDIRS) $(TOOL_DIRS)
|
||||
else
|
||||
__SUBDIRS = $(DUAL_SUBDIRS) $(TOOL_DIRS)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
SUBDIRS = $(strip $(foreach dir, $(__SUBDIRS),$(wildcard $(dir))))
|
||||
|
||||
# overrides DOCSUBDIRS = $(SUBDIRS) in rules-lib.$(WIND_HOST_TYPE) to
|
||||
# make sure all necessary doc directories are built.
|
||||
|
||||
DOCSUBDIRS = $(COMMON_SUBDIRS) $(DUAL_SUBDIRS) $(TOOL_DIRS) $(VXSIM_SUBDIRS)
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
include $(TGT_DIR)/h/make/rules.vxbus
|
||||
|
||||
LOCAL_RCLEAN = $(SCGEN_DERIVED_FILES)
|
||||
|
||||
# If doing a doc build, ensure arch/Makefile is built.
|
||||
# The rules are in $(TGT_DIR)/h/make/rules-lib.unix
|
||||
|
||||
man: $(TGT_DIR)/src/arch/Makefile
|
||||
|
||||
clean_interface :
|
||||
cd $(INTERFACE_SUBDIR) && $(MAKE) clean_interface
|
||||
@@ -0,0 +1,73 @@
|
||||
# Makefile - makefile for target/src/aim
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01w,08mar12,h_k reverted the single CPU_VARIANT build. (WIND00320752)
|
||||
# 01v,22nov11,x_s add support for building a single CPU_VARIANT for PPC32 SMP
|
||||
# 01u,05jul10,liu add aimFppShow.c to support fppTaskRegsShow. (WIND00192339)
|
||||
# 01t,04oct10,kk add back the build for aimCacheLib.c and aimCacheSyctl.c
|
||||
# for 64bit
|
||||
# 01s,30sep10,kk disable files for building for LP64
|
||||
# 01r,09sep10,jpb Added aimFuncBind.o
|
||||
# 01q,26feb10,pch small footprint
|
||||
# 01p,01feb10,elp disable build for simulator.
|
||||
# 01o,08jun09,jb Disable aimMmuLib build for pentium family
|
||||
# 01n,20apr05,dr SPR 108100 - Added aimFppLib.c
|
||||
# 01m,14jun04,job Removed an unnecessary include of defs.library
|
||||
# 01l,10jun04,sru build aimCacheLib.o for all architectures
|
||||
# 01k,08jun04,sru Added aimMmuBaseLib.o
|
||||
# 01j,02jun04,mil Made libaim PPC32 generic.
|
||||
# 01i,30apr04,pch clean up; build for selected PPC variants
|
||||
# 01h,27apr04,rec add sysctl support
|
||||
# 01g,01apr04,scm add Arm/XScale cache AIM support...
|
||||
# 01f,26mar04,slk Update so MIPS32 and MIPS64 CPUs include aimCacheLib.o
|
||||
# 01e,17feb04,pch remove PPC32 hack, no longer needed
|
||||
# 01d,23dec03,kab Remove aimCacheLib until stable
|
||||
# 01c,24nov03,sru fix PPC32 builds
|
||||
# 01b,21oct03,sru add aimMmuShow.c
|
||||
# 01a,14apr03,jb created
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the aim library
|
||||
#
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
|
||||
DOC_FILES_COMMON= \
|
||||
aimCacheLib.c \
|
||||
aimFppLib.c
|
||||
|
||||
LIB_BASE_NAME = aim
|
||||
|
||||
OBJS_COMMON = aimCacheLib.o aimFppLib.o aimFuncBind.o aimFppShow.o
|
||||
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
ifndef _WRS_CONFIG_MEM_ALLOT
|
||||
# Sysctl and MMU require memory management
|
||||
OBJS_COMMON += aimMmuBaseLib.o aimMmuShow.o aimMmuSysctl.o aimCacheSysctl.o
|
||||
endif
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),$(filter $(VX_CPU_FAMILY),pentium simpc simlinux simso))
|
||||
DOC_FILES=$(DOC_FILES_COMMON)
|
||||
else
|
||||
DOC_FILES=$(DOC_FILES_COMMON) aimMmuLib.c
|
||||
endif
|
||||
|
||||
ifneq ($(VX_CPU_FAMILY),$(filter $(VX_CPU_FAMILY),pentium simpc simlinux simso))
|
||||
ifndef _WRS_CONFIG_MEM_ALLOT
|
||||
OBJS_COMMON += aimMmuLib.o
|
||||
endif
|
||||
endif
|
||||
|
||||
# 64bit only utilizes the following files, all other files, such as
|
||||
# aimMmuShow.o and aimMmuLib.c are not used and therefore not built.
|
||||
|
||||
ifdef _WRS_CONFIG_LP64
|
||||
OBJS_COMMON = aimMmuBaseLib.o aimFppLib.o aimFuncBind.o aimMmuSysctl.o \
|
||||
aimCacheLib.o aimCacheSysctl.o
|
||||
endif
|
||||
|
||||
OBJS= $(OBJS_COMMON)
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,171 @@
|
||||
/* aimCacheSysctl.c - Cache abstraction sysctl support functions */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2005, 2007 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01j,01jun07,pad Replaced inclusion of sys/sysctl.h with private/sysctlP.h.
|
||||
01i,25aug05,h_k converted INCLUDE_CACHE_EXTRA to _WRS_SUPPORT_CACHE_EXTRA.
|
||||
01h,23jul05,mil Scaled down for minimal kernel.
|
||||
01g,30sep04,mdo Documentation fixes for apigen
|
||||
01f,14jun04,job Changed more OID_AUTO to fixed values
|
||||
01e,07jun04,job Changed OID_AUTO to fixed values
|
||||
01d,20may04,mem If used, create hw.cache node here.
|
||||
01c,11may04,rec fix PPC405 link error
|
||||
01b,04may04,rec review comments
|
||||
01a,27apr04,rec written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
|
||||
INCLUDE FILES:
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <aimCacheLib.h>
|
||||
#include <private/sysctlP.h> /* brings in sysctl_add_oid_internal() */
|
||||
|
||||
/* needed for sysctl macro expansion */
|
||||
|
||||
#ifndef PRINTF
|
||||
#define _SYSCTL_DEBUG
|
||||
#ifdef _SYSCTL_DEBUG
|
||||
#define PRINTF printf
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* externals */
|
||||
|
||||
SYSCTL_DECL_NODE_EXT (hw);
|
||||
|
||||
/* locals */
|
||||
|
||||
/* globals */
|
||||
|
||||
SYSCTL_DECL_NODE (cache);
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* aimCacheSysctlInit - AIM Cache sysctl initialization
|
||||
*
|
||||
* This routine initializes cache optional sysctl support.
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
STATUS aimCacheSysctlInit (void)
|
||||
{
|
||||
/*
|
||||
* create cache leaves for each defined cache type
|
||||
* Note: for loop won't work because of initializers in enumeration
|
||||
*/
|
||||
|
||||
SYSCTL_NODE (hw, HW_CACHE, cache, CTLFLAG_RW, NULL, "cache" );
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_I].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_INSTR_SIZE, icacheSize, CTLFLAG_RD,
|
||||
&cacheAimInfo[CACHE_TYPE_I].cacheSize, 0,
|
||||
"instruction cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_INSTR_LINE_SIZE, icacheLineSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_I].cacheLineSize, 0,
|
||||
"instruction cache Line size");
|
||||
}
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_D].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_DATA_SIZE, dcacheSize, CTLFLAG_RD,
|
||||
&cacheAimInfo[CACHE_TYPE_D].cacheSize, 0,
|
||||
"data cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_DATA_LINE_SIZE,
|
||||
dcacheLineSize, CTLFLAG_RD,
|
||||
&cacheAimInfo[CACHE_TYPE_D].cacheLineSize, 0,
|
||||
"data cache Line size");
|
||||
}
|
||||
|
||||
#ifdef _WRS_SUPPORT_CACHE_EXTRA
|
||||
if (cacheAimInfo[CACHE_TYPE_B].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_BRANCH_SIZE, branchSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_B].cacheSize, 0,
|
||||
"branch cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_BRANCH_LINE_SIZE, branchLineSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_B].cacheLineSize, 0,
|
||||
"branch cache Line size");
|
||||
}
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_S].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_L2_SIZE, L2Size,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_S].cacheSize, 0,
|
||||
"L2 cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_L2_LINE_SIZE, L2LineSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_S].cacheLineSize, 0,
|
||||
"L2 cache Line size");
|
||||
}
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_T].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_L3_SIZE, L3Size,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_T].cacheSize, 0,
|
||||
"L3 cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_L3_LINE_SIZE, L3LineSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_T].cacheLineSize, 0,
|
||||
"L3 cache Line size");
|
||||
}
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_IL].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_INSTR_TLB_SIZE, instructionTLBSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_IL].cacheSize, 0,
|
||||
"Instruction TLB cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_INSTR_TLB_LINE_SIZE,
|
||||
instructionTLBLineSize, CTLFLAG_RD,
|
||||
&cacheAimInfo[CACHE_TYPE_IL].cacheLineSize, 0,
|
||||
"Instruction TLB cache Line size");
|
||||
}
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_DL].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_DATA_TLB_SIZE, dataTLBSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_DL].cacheSize, 0,
|
||||
"Data TLB cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_DATA_TLB_LINE_SIZE, dataTLBLineSize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_DL].cacheLineSize, 0,
|
||||
"Data TLB cache Line size");
|
||||
}
|
||||
|
||||
if (cacheAimInfo[CACHE_TYPE_A].cacheExists)
|
||||
{
|
||||
SYSCTL_INT (cache, HW_CACHE_ALTPRI_SIZE, alternatePrimarySize,
|
||||
CTLFLAG_RD, &cacheAimInfo[CACHE_TYPE_A].cacheSize, 0,
|
||||
"Alternate Primary cache size");
|
||||
SYSCTL_INT (cache, HW_CACHE_ALTPRI_LINE_SIZE,
|
||||
alternatePrimaryLineSize, CTLFLAG_RD,
|
||||
&cacheAimInfo[CACHE_TYPE_A].cacheLineSize, 0,
|
||||
"Alternate Primary cache Line size");
|
||||
}
|
||||
#endif /* _WRS_SUPPORT_CACHE_EXTRA */
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/* aimFppLib.c - floating-point unit support library for AIM */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2009-2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,28sep10,scm use TASK_ID for 64 bit compatibility...
|
||||
01c,09jun09,cww Made coprocLib header private
|
||||
01b,22apr05,dr Added aimFppLibInit().
|
||||
01a,19apr05,dr created.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This is the Architecture Independant Manager (AIM) for VxWorks floating
|
||||
point support. It contains floating point routines that are common to
|
||||
all CPU architectures supported by VxWorks.
|
||||
|
||||
SEE ALSO: fppArchLib, coprocLib
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <fppLib.h>
|
||||
#include <private/coprocLibP.h>
|
||||
|
||||
#ifdef _WRS_PAL_COPROC_LIB
|
||||
/***************************************************************************
|
||||
*
|
||||
* aimFppLibInit - Initialize the AIM FPU library
|
||||
*
|
||||
* Initialize the AIM FPU library.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO:
|
||||
*/
|
||||
|
||||
void aimFppLibInit
|
||||
(
|
||||
void
|
||||
)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* fppTaskRegsSet - Sets FPU context for a task
|
||||
*
|
||||
* Sets the FPU context for a task.
|
||||
*
|
||||
* RETURNS: OK on success.
|
||||
* ERROR otherwise
|
||||
*
|
||||
* ERRNO: S_coprocLib_INVALID_OPERATION
|
||||
* S_coprocLib_INVALID_ARGUMENT
|
||||
* S_coprocLib_NO_COPROC_SUPPORT
|
||||
*/
|
||||
|
||||
STATUS fppTaskRegsSet
|
||||
(
|
||||
TASK_ID task,
|
||||
FPREG_SET *pFpRegSet
|
||||
)
|
||||
{
|
||||
return coprocTaskRegsSet (task, VX_FP_TASK, (void *) pFpRegSet);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* fppTaskRegsGet - Gets FPU context for a task
|
||||
*
|
||||
* Gets the FPU context for a task.
|
||||
*
|
||||
* RETURNS: OK on success.
|
||||
* ERROR otherwise
|
||||
*
|
||||
* ERRNO: S_coprocLib_INVALID_OPERATION
|
||||
* S_coprocLib_INVALID_ARGUMENT
|
||||
* S_coprocLib_NO_COPROC_SUPPORT
|
||||
*/
|
||||
|
||||
STATUS fppTaskRegsGet
|
||||
(
|
||||
TASK_ID task,
|
||||
FPREG_SET *pFpRegSet
|
||||
)
|
||||
{
|
||||
return coprocTaskRegsGet (task, VX_FP_TASK, (void *) pFpRegSet);
|
||||
}
|
||||
|
||||
#endif /* _WRS_PAL_COPROC_LIB */
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/* aimFppShow.c - floating-point show routines */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify, or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01q,02nov11,swu remove _func_fppTaskRegsShow from funcBind. (WIND00245382)
|
||||
01p,05jul10,liu created based on fppShow.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This library provides the routines necessary to show a task's optional
|
||||
floating-point context. To use this facility, it must first be
|
||||
installed using aimFppShowInit(), which is called automatically
|
||||
when the floating-point show facility is configured into VxWorks
|
||||
using either of the following methods:
|
||||
.iP
|
||||
If you use the configuration header files, define
|
||||
INCLUDE_SHOW_ROUTINES in config.h.
|
||||
.iP
|
||||
If you use the Tornado project facility, select INCLUDE_HW_FP_SHOW.
|
||||
.LP
|
||||
|
||||
This library enhances task information routines, such as ti(), to display
|
||||
the floating-point context.
|
||||
|
||||
INCLUDE FILES: fppLib.h
|
||||
|
||||
*/
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "stdio.h"
|
||||
#include "regs.h"
|
||||
#include "fppLib.h"
|
||||
#include "private/coprocLibP.h"
|
||||
|
||||
/* global variables */
|
||||
|
||||
#if defined (_WRS_PAL_COPROC_LIB)
|
||||
extern char *fppTaskRegsCFmt;
|
||||
extern char *fppTaskRegsDFmt;
|
||||
#else /* _WRS_PAL_COPROC_LIB */
|
||||
char *fppTaskRegsCFmt = "%-6.6s = %8x";
|
||||
char *fppTaskRegsDFmt = "%-6.6s = %8g";
|
||||
#endif /* _WRS_PAL_COPROC_LIB */
|
||||
|
||||
#if !defined _WRS_FLOAT_TYPE
|
||||
#define _WRS_FLOAT_TYPE double
|
||||
#endif /* _WRS_FLOAT_TYPE */
|
||||
|
||||
#if !defined _WRS_FP_REG_TEMP
|
||||
#define _WRS_FP_REG_TEMP(ix) fpTmp = (_WRS_FLOAT_TYPE *) ((int)&fpRegSet + fpRegName[(ix)].regOff)
|
||||
#endif /* _WRS_FP_REG_TEMP */
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
void fppTaskRegsShow(TASK_ID task);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* aimFppShowInit - initialize the floating-point show facility
|
||||
*
|
||||
* This routine links the floating-point show facility into the VxWorks system.
|
||||
* It is called automatically when the floating-point show facility is
|
||||
* configured into VxWorks using either of the following methods:
|
||||
* .iP
|
||||
* If you use the configuration header files, define
|
||||
* INCLUDE_SHOW_ROUTINES in config.h.
|
||||
* .iP
|
||||
* If you use the Tornado project facility, select INCLUDE_HW_FP_SHOW.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void aimFppShowInit (void)
|
||||
{
|
||||
/* avoid direct coupling with fppShow with this global variable */
|
||||
|
||||
#if !defined (_WRS_PAL_COPROC_LIB)
|
||||
_func_fppTaskRegsShow = fppTaskRegsShow;
|
||||
#endif /* _WRS_PAL_COPROC_LIB */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* fppTaskRegsShow - print the contents of a task's floating-point registers
|
||||
*
|
||||
* This routine prints to standard output the contents of a task's
|
||||
* floating-point registers.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void fppTaskRegsShow
|
||||
(
|
||||
TASK_ID task /* task to display floating point registers for */
|
||||
)
|
||||
{
|
||||
int ix;
|
||||
_WRS_FLOAT_TYPE *fpTmp;
|
||||
int * fpCtlTmp;
|
||||
FPREG_SET fpRegSet;
|
||||
|
||||
#if defined (_WRS_NEED_DOUBLE_TMP)
|
||||
double doubleTmp;
|
||||
double *fpDoubleTmp = &doubleTmp;
|
||||
#endif /* _WRS_NEED_DOUBLE_TMP */
|
||||
|
||||
if ((fppProbe() != OK) || (fppTaskRegsGet (task, &fpRegSet) == ERROR))
|
||||
return;
|
||||
|
||||
/* Some architectures organize floats sequentially, but to
|
||||
* display them as doubles the floats need to be word swapped.
|
||||
*/
|
||||
|
||||
if (fppDisplayHookRtn != NULL)
|
||||
(* fppDisplayHookRtn) (&fpRegSet);
|
||||
|
||||
/* print floating point control registers */
|
||||
|
||||
for (ix = 0; fpCtlRegName[ix].regName != (char *) NULL; ix++)
|
||||
{
|
||||
if ((ix % 4) == 0)
|
||||
printf ("\n");
|
||||
else
|
||||
printf ("%3s","");
|
||||
|
||||
fpCtlTmp = (int *) ((int)&fpRegSet + fpCtlRegName[ix].regOff);
|
||||
printf (fppTaskRegsCFmt, fpCtlRegName[ix].regName, *fpCtlTmp);
|
||||
}
|
||||
|
||||
/* print floating point data registers */
|
||||
|
||||
for (ix = 0; fpRegName[ix].regName != (char *) NULL; ix++)
|
||||
{
|
||||
if ((ix % 4) == 0)
|
||||
printf ("\n");
|
||||
else
|
||||
printf ("%3s","");
|
||||
|
||||
/* copy reg value into fpTmp, print it from there */
|
||||
|
||||
_WRS_FP_REG_TEMP(ix);
|
||||
printf (fppTaskRegsDFmt, fpRegName[ix].regName, *fpTmp);
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* aimFuncBind.c - aim function binding library */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,30aug10,jpb Created
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module provides aim function pointers and global variables
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
|
||||
STATUS (*_func_aimMmuLockRegionsImport)(void);
|
||||
@@ -0,0 +1,113 @@
|
||||
/* aimMmuBaseLib.c - MMU Architecture Independent Manager */
|
||||
|
||||
/* Copyright 2004, 2005, 2012 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01e,06sep12,mpc Removed build warnings. (WIND00358280)
|
||||
01d,22aug05,mil Added comments about usage of aimMmuBaseLibInit.
|
||||
01c,19oct04,zl fixed pageSize and blockSize initialization (SPR #102620).
|
||||
01b,30sep04,mdo Documentation fixes for apigen
|
||||
01a,03jun04,sru written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
This library contains the basic Architecture Independent Manager (AIM)
|
||||
initializer for architecture dependent MMU subsystem that does not
|
||||
use the full AIM implementation, which can be found in aimMmuLib.c.
|
||||
|
||||
All MMU subsystems have to export two properties into the 'sysctl'
|
||||
subsystem: pageSize and blockSize. To accomplish this, aimMmuSysctl.c
|
||||
passes two pointers-to-integer into the 'sysctl' subsystem. The
|
||||
pointers refer to two structure elements:
|
||||
|
||||
mmuArchLibAttrs.blockSize
|
||||
mmuArchLibAttrs.pageSize
|
||||
|
||||
This means that, regardless of how the MMU subsystem is managed, these
|
||||
two structure members must be available so they can be used by 'sysctl'.
|
||||
|
||||
The 'mmuArchLibAttrs' data structure is shared between the MMU AIM and
|
||||
the AD-MMU. If an AD-MMU makes full use of the AIM, it is _not_
|
||||
required to initialize either the .pageSize or .blockSize structure
|
||||
members. Instead, it initializes the .pageSizeMask and
|
||||
.pageTblNumEntries members, and the AIM uses those members to initialize
|
||||
.pageSize and .blockSize.
|
||||
|
||||
1) AD-MMU uses the full AIM, so it initializes .pageSizeMask and
|
||||
.pageTblNumEntries, and calls aimMmuLibInit() to do the remainder of the
|
||||
work.
|
||||
|
||||
2) AD-MMU doesn't use the full AIM, so it doesn't do _any_
|
||||
initialization of the structure members in mmuArchLibAttrs. Instead, it
|
||||
calls aimMmuBaseLibInit(). This function takes care of initializing
|
||||
.pageSize and .blockSize so that they can be used by 'sysctl'.
|
||||
|
||||
|
||||
INCLUDE FILES: vmLib.h, aimMmuLib.h
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
DOCUMENTATION
|
||||
|
||||
This library contains the basic Architecture Independent Manager (AIM)
|
||||
initializer for architecture dependent MMU subsystem that does not
|
||||
use the full AIM implementation, which can be found in aimMmuLib.c.
|
||||
*/
|
||||
|
||||
/* Includes */
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "private/vmLibP.h"
|
||||
#include "aimMmuLib.h"
|
||||
|
||||
/* Externs */
|
||||
|
||||
IMPORT MMU_LIB_FUNCS mmuLibFuncs;
|
||||
|
||||
/* Globals */
|
||||
|
||||
MMU_ARCH_LIB_ATTRS mmuArchLibAttrs;
|
||||
MMU_ARCH_LIB_FUNCS mmuArchLibFuncs;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* aimMmuBaseLibInit - Initialize the base portion of the MMU AIM.
|
||||
*
|
||||
* aimMmuBaseLibInit is called by all architecture-specific MMU
|
||||
* implementations. Those that utilize the MMU AIM call this function
|
||||
* indirectly (via aimMmuLibInit); those that do not utilize the software
|
||||
* abstractions of the AIM call this function directly. At present, the
|
||||
* base library does not implement any value-added services. This
|
||||
* library exists to give a standard AIM-centric interface to all
|
||||
* MMU implementations.
|
||||
*
|
||||
* RETURNS: OK.
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
STATUS aimMmuBaseLibInit (void)
|
||||
{
|
||||
/* initialize region size if it isn't already configured */
|
||||
|
||||
if (mmuArchLibAttrs.blockSize == 0)
|
||||
mmuArchLibAttrs.blockSize = (UINT)mmuLibFuncs.mmuBlockSizeGet();
|
||||
|
||||
/* initialize page size if it isn't already configured */
|
||||
|
||||
if (mmuArchLibAttrs.pageSize == 0)
|
||||
mmuArchLibAttrs.pageSize = (UINT)mmuLibFuncs.mmuPageSizeGet();
|
||||
|
||||
return OK;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,409 @@
|
||||
/* aimMmuShow.c - MMU Architecture Independent Manager Show Routines */
|
||||
|
||||
/*
|
||||
* Copyright 1984-2004, 2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01e,14jan10,cwl Remove the function aimMmuShowInit(). (WIND00184839)
|
||||
01d,30sep04,mdo Documentation fixes for apigen
|
||||
01c,18aug04,sru Added aimMmuPageTableShow show routine.
|
||||
01b,29apr04,dtr Adding optimization show routine.
|
||||
01a,01oct03,jtp written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
This library displays statistics for the Architecture Independent
|
||||
Manager (AIM) for the VxWorks MMU subsystem.
|
||||
|
||||
INCLUDE FILES:
|
||||
*/
|
||||
|
||||
/*
|
||||
DOCUMENTATION
|
||||
|
||||
This library display statistics for the Architecture Independent Manager
|
||||
for the VxWorks MMU subsystem. aimMmuMapShow displays the map of valid
|
||||
pages. Example:
|
||||
|
||||
-> aimMmuMapShow
|
||||
|
||||
Valid Page Map for context 1
|
||||
|
||||
Virtual Adrs. Range # Pages
|
||||
----------------------------
|
||||
00000000 - 07ffffff 32768
|
||||
80000000 - 81ffffff 8192
|
||||
a0000000 - a1ffffff 8192
|
||||
c0000000 - c0001fff 2
|
||||
d8000000 - d800ffff 16
|
||||
d8800000 - d88fffff 256
|
||||
dec00000 - dec00fff 1
|
||||
dec80000 - dec80fff 1
|
||||
ded00000 - ded00fff 1
|
||||
e0000000 - e0000fff 1
|
||||
e8000000 - e8001fff 2
|
||||
e8200000 - e8200fff 1
|
||||
e8300000 - e8300fff 1
|
||||
ff800000 - ffbfffff 1024
|
||||
fff80000 - ffffffff 128
|
||||
|
||||
Mapped space 207200256 bytes in 50586 PTEs
|
||||
|
||||
Page Tables use 917504 bytes in 56 tables
|
||||
Region Tables use 4096 bytes in 1 tables
|
||||
Total overhead 921600 bytes ( 0.5% of all mapped)
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* Includes */
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "vmLib.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "aimMmuLib.h"
|
||||
|
||||
|
||||
/* Defines */
|
||||
|
||||
#define ATTR(a) mmuArchLibAttrs.a
|
||||
#define FUNC(f) mmuArchLibFuncs.f
|
||||
|
||||
/* Typedefs */
|
||||
|
||||
/* Externals */
|
||||
|
||||
IMPORT MMU_CONTEXT_TBL * aimMmuContextTbl;
|
||||
IMPORT MMU_ARCH_LIB_ATTRS mmuArchLibAttrs;
|
||||
IMPORT MMU_ARCH_LIB_FUNCS mmuArchLibFuncs;
|
||||
IMPORT MMU_REGION_TBL * aimMmuNullRegionTbl;
|
||||
IMPORT MMU_PAGE_TBL * aimMmuNullPageTbl;
|
||||
|
||||
/* Globals */
|
||||
|
||||
/* Forward Declarations */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* aimMmuMapShow - display the memory map for a context
|
||||
*
|
||||
* Displays the memory map of valid virtual pages for the identified
|
||||
* context. 0 means the global context.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
void aimMmuMapShow
|
||||
(
|
||||
UINT context /* context ID for map */
|
||||
)
|
||||
{
|
||||
struct pte { UINT32 data; };
|
||||
struct pte ** regBase; /* base of region table */
|
||||
struct pte * pageBase; /* base of page table */
|
||||
struct pte * pPte; /* pointer to a specific PTE */
|
||||
int regIx; /* index into region table */
|
||||
int pageIx; /* index into page table */
|
||||
int numPageTbls = 0; /* number of non-NULL page tables */
|
||||
int numValidPtes = 0; /* total number of valid PTEs */
|
||||
BOOL blockValid = FALSE; /* validity of current block of PTEs */
|
||||
UINT32 blockBase = 0; /* lowest addr in curr block of PTEs */
|
||||
UINT blockSize = 0; /* size of current block of PTEs */
|
||||
UINT32 mappedBytes; /* total count of mapped bytes */
|
||||
UINT32 regTblBytes; /* # of bytes for region table */
|
||||
UINT32 pageTblBytes; /* # of bytes for page tables */
|
||||
UINT32 overheadPerMil; /* % of table overhead times 10 */
|
||||
|
||||
if (context < ATTR(contextMin))
|
||||
{
|
||||
context = ATTR(contextMin);
|
||||
}
|
||||
|
||||
if (context > ATTR(contextMax))
|
||||
{
|
||||
context = ATTR(contextMax);
|
||||
}
|
||||
|
||||
if (aimMmuContextTbl == NULL)
|
||||
{
|
||||
printf("no context table allocated\n");
|
||||
return;
|
||||
}
|
||||
|
||||
regBase = (struct pte **) aimMmuContextTbl [context];
|
||||
if (regBase == (struct pte **) aimMmuNullRegionTbl)
|
||||
{
|
||||
printf("no region table allocated for context %d\n", context);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("\tValid Page Map for context %d\n\n", context);
|
||||
printf("\tVirtual Adrs. Range # Pages\n");
|
||||
printf("\t----------------------------\n");
|
||||
|
||||
#define BLOCK_PRINT(base, size, pgSize) \
|
||||
printf("\t%08x - %08x %7d\n", (base), ((base)+(size)-1), (size)/(pgSize));
|
||||
|
||||
for (regIx = 0; regIx < ATTR(regionTblNumEntries); regIx++)
|
||||
{
|
||||
pageBase = regBase [regIx];
|
||||
|
||||
if (pageBase == (struct pte *) aimMmuNullPageTbl)
|
||||
{
|
||||
if (blockValid == TRUE)
|
||||
{
|
||||
BLOCK_PRINT(blockBase, blockSize, ATTR(pageSize));
|
||||
blockValid = FALSE;
|
||||
blockBase += blockSize;
|
||||
blockSize = 0;
|
||||
}
|
||||
|
||||
blockSize += ATTR(pageTblNumEntries) * ATTR(pageSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
numPageTbls++;
|
||||
|
||||
for (pageIx = 0; pageIx < ATTR(pageTblNumEntries); pageIx++)
|
||||
{
|
||||
pPte = (struct pte *)((UINT32)pageBase + pageIx * ATTR(pteSize));
|
||||
|
||||
if (FUNC(mmuPteValidGet)(pPte) == FALSE)
|
||||
{
|
||||
if (blockValid == TRUE)
|
||||
{
|
||||
BLOCK_PRINT(blockBase, blockSize, ATTR(pageSize));
|
||||
blockValid = FALSE;
|
||||
blockBase += blockSize;
|
||||
blockSize = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (blockValid == FALSE)
|
||||
{
|
||||
blockValid = TRUE;
|
||||
blockBase += blockSize;
|
||||
blockSize = 0;
|
||||
}
|
||||
|
||||
numValidPtes++;
|
||||
}
|
||||
|
||||
blockSize += ATTR(pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (blockSize != 0 && blockValid == TRUE)
|
||||
{
|
||||
BLOCK_PRINT(blockBase, blockSize, ATTR(pageSize));
|
||||
}
|
||||
|
||||
mappedBytes = ATTR(pageSize) * numValidPtes;
|
||||
pageTblBytes = numPageTbls * ATTR(pteSize) * ATTR(pageTblNumEntries);
|
||||
regTblBytes = sizeof(void *) * ATTR(regionTblNumEntries);
|
||||
overheadPerMil =
|
||||
((pageTblBytes + regTblBytes) * 1000 + mappedBytes - 1) / mappedBytes;
|
||||
|
||||
printf("\n");
|
||||
printf(" Mapped space %10d bytes in %7d PTEs\n\n",
|
||||
mappedBytes, numValidPtes);
|
||||
printf(" Page Tables use %10d bytes in %7d tables\n",
|
||||
pageTblBytes, numPageTbls);
|
||||
printf(" Region Tables use %10d bytes in %7d tables\n", regTblBytes, 1);
|
||||
printf(" Total overhead %10d bytes", pageTblBytes + regTblBytes);
|
||||
printf(" (%2d.%01d%% of all mapped)\n",
|
||||
overheadPerMil / 10, overheadPerMil % 10);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* aimMmuOptimizeMemShow - display the optimized pages for Translation tbl
|
||||
*
|
||||
* Displays the memory map of valid optimized virtual pages for the
|
||||
* identified context. 0 will mean default to global trans tbl
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
void aimMmuOptimizeMemShow
|
||||
(
|
||||
int context
|
||||
)
|
||||
{
|
||||
MMU_REGION_TBL *pRegionTbl;
|
||||
MMU_PAGE_TBL *pPageTbl;
|
||||
void *pPte,*pLastPte;
|
||||
UINT regionLoop,pageLoop,pageSize,totalSizeOptimized=0;
|
||||
VIRT_ADDR virtAddr;
|
||||
UINT totalLocalSizeOptimized=0,lastPageSize=0,startVirtAddr=0;
|
||||
|
||||
|
||||
if (context < ATTR(contextMin))
|
||||
{
|
||||
context = ATTR(contextMin);
|
||||
}
|
||||
|
||||
if (context > ATTR(contextMax))
|
||||
{
|
||||
context = ATTR(contextMax);
|
||||
}
|
||||
|
||||
if (aimMmuContextTbl == NULL)
|
||||
{
|
||||
printf("no context table allocated\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("|VIRT ADDR|\t|PAGE SIZE|\t|END ADRS|\t|NUM PAGES|\n");
|
||||
|
||||
pRegionTbl= (MMU_REGION_TBL *)aimMmuContextTbl[context];
|
||||
|
||||
for (regionLoop=0;regionLoop<ATTR(regionTblNumEntries);regionLoop++)
|
||||
{
|
||||
virtAddr = regionLoop * ATTR(blockSize);
|
||||
if (pRegionTbl[regionLoop] == NULL)
|
||||
continue;
|
||||
|
||||
pPageTbl = pRegionTbl[regionLoop];
|
||||
|
||||
for (pageLoop=0;pageLoop<ATTR(pageTblNumEntries);pageLoop++)
|
||||
{
|
||||
pPte = &pPageTbl[pageLoop * ATTR(pteSize)];
|
||||
pageSize = FUNC(mmuPtePageSizeGet)(pPte);
|
||||
|
||||
if ((pageSize!=lastPageSize) && (totalLocalSizeOptimized !=0))
|
||||
{
|
||||
printf("0x%8x\t0x%8x\t0x%8x\t0x%8x\n",startVirtAddr,lastPageSize,(startVirtAddr + totalLocalSizeOptimized),totalLocalSizeOptimized/lastPageSize);
|
||||
startVirtAddr=0;
|
||||
totalSizeOptimized +=totalLocalSizeOptimized;
|
||||
totalLocalSizeOptimized=0;
|
||||
}
|
||||
|
||||
if (pageSize>ATTR(pageSize))
|
||||
{
|
||||
if (startVirtAddr==0)startVirtAddr=virtAddr;
|
||||
totalLocalSizeOptimized +=pageSize;
|
||||
pageLoop+=(pageSize>>ATTR(pageShift)) - 1;
|
||||
virtAddr+=pageSize - ATTR(pageSize);
|
||||
lastPageSize = pageSize;
|
||||
}
|
||||
virtAddr +=ATTR(pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\n\ntotalSizeOptimized : 0x%x\n\n",totalSizeOptimized);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* aimMmuPageTableShow - Display the raw PTEs for the requested context.
|
||||
*
|
||||
* aimMmuPageTableShow displays the raw PTEs for the requested context.
|
||||
* If a virtual address range is provided, all of the PTES that provide
|
||||
* a mapping for that virtual address range are displayed. If only a
|
||||
* starting address is provided, the single PTE for that virtual address
|
||||
* is displayed.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO
|
||||
*/
|
||||
|
||||
void aimMmuPageTableShow
|
||||
(
|
||||
UINT context, /* context ID for map */
|
||||
VIRT_ADDR vaStart, /* start of range to show */
|
||||
VIRT_ADDR vaEnd /* end of range to show */
|
||||
)
|
||||
{
|
||||
MMU_REGION_TBL * pRegionTbl;
|
||||
MMU_PAGE_TBL * pPageTbl;
|
||||
VIRT_ADDR pteVirtAddr;
|
||||
int regIx;
|
||||
int pageIx;
|
||||
int i;
|
||||
|
||||
/* verify that the provided context is valid. */
|
||||
|
||||
if (context < ATTR(contextMin) || context > ATTR(contextMax))
|
||||
{
|
||||
printf ("context %d out of range [%d..%d]\n",
|
||||
context, ATTR(contextMin), ATTR(contextMax));
|
||||
return;
|
||||
}
|
||||
|
||||
/* get region table for the context */
|
||||
|
||||
pRegionTbl = aimMmuContextTbl [context];
|
||||
if (pRegionTbl == aimMmuNullRegionTbl)
|
||||
{
|
||||
printf ("context %d not currently in use\n", context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if vaStart is not specified, dump whole address space */
|
||||
|
||||
if (vaStart == 0)
|
||||
{
|
||||
vaEnd = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
vaStart = ROUND_DOWN (vaStart, ATTR(pageSize));
|
||||
if (vaEnd == 0)
|
||||
vaEnd = vaStart + ATTR(pageSize) - 1;
|
||||
}
|
||||
|
||||
printf ("dump PTEs for virtual address range [%x,%x]\n", vaStart, vaEnd);
|
||||
|
||||
/*
|
||||
* scan region table for page tables. For non-NULL page tables,
|
||||
* dump any PTEs that are within the requested address range.
|
||||
*/
|
||||
|
||||
for (regIx = 0; regIx < ATTR(regionTblNumEntries); regIx++)
|
||||
{
|
||||
pPageTbl = pRegionTbl [regIx];
|
||||
|
||||
if (pPageTbl == aimMmuNullPageTbl)
|
||||
continue;
|
||||
|
||||
for (pageIx = 0; pageIx < ATTR(pageTblNumEntries); pageIx++)
|
||||
{
|
||||
pteVirtAddr = (regIx * ATTR(blockSize) +
|
||||
pageIx * ATTR(pageSize));
|
||||
|
||||
if ((vaStart <= pteVirtAddr) && (pteVirtAddr <= vaEnd))
|
||||
{
|
||||
UINT32 *pPte = (UINT32 *) (pPageTbl + pageIx * ATTR(pteSize));
|
||||
|
||||
printf ("%08x: [", pteVirtAddr);
|
||||
for (i = 0; i < ATTR(pteSize) >> 2; i++)
|
||||
{
|
||||
printf ("%s%08x", ((i == 0) ? "" : ","), pPte[i]);
|
||||
}
|
||||
printf ("]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/* aimMmuSysctl.c - aimMmuitecture abstraction sysctl support functions */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004, 2007 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01j,01jun07,pad Replaced inclusion of sys/sysctl.h with private/sysctlP.h.
|
||||
01i,30sep04,mdo Documentation fixes for apigen
|
||||
01h,14jun04,job Changed move OID_AUTOs to fixed values
|
||||
01g,09jun04,sru Removed hw.mmu.tlbEntries; it was redundant, since
|
||||
hw.pal.cpu.nTlbEntries provides the same information.
|
||||
01f,08jun04,sru Reworked to use MMU AIM attributes structure.
|
||||
01e,07jun04,job Changed OID_AUTO to fixed values
|
||||
01d,20may04,mem If used, create hw.mmu node here.
|
||||
01c,11may04,rec fix PPC405 link error
|
||||
01b,29apr04,rec review comments
|
||||
01a,27apr04,rec written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
|
||||
INCLUDE FILES:
|
||||
*/
|
||||
|
||||
#include "vxWorks.h"
|
||||
#include "aimMmuBaseLib.h"
|
||||
#include "private/sysctlP.h" /* brings in sysctl_add_oid_internal() */
|
||||
|
||||
/* needed for sysctl macro expansion */
|
||||
|
||||
#ifndef PRINTF
|
||||
#define _SYSCTL_DEBUG
|
||||
#ifdef _SYSCTL_DEBUG
|
||||
#define PRINTF printf
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* externals */
|
||||
|
||||
SYSCTL_DECL_NODE_EXT (hw);
|
||||
IMPORT MMU_ARCH_LIB_ATTRS mmuArchLibAttrs;
|
||||
|
||||
/* globals */
|
||||
|
||||
SYSCTL_DECL_NODE (mmu);
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* aimMmuSysctlInit - AIM Mmu sysctl initialization
|
||||
*
|
||||
* This routine initializes MMU sysctl support.
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
* ERRNO
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
STATUS aimMmuSysctlInit (void)
|
||||
{
|
||||
/* hw.mmu */
|
||||
|
||||
SYSCTL_NODE (hw, HW_MMU, mmu, CTLFLAG_RW, NULL, "mmu" );
|
||||
|
||||
/* hw.mmu.pageSize */
|
||||
|
||||
SYSCTL_INT (mmu, HW_MMU_PAGESIZE, pageSize, CTLFLAG_RD,
|
||||
&mmuArchLibAttrs.pageSize, 0, "");
|
||||
|
||||
/* hw.mmu.blockSize */
|
||||
|
||||
SYSCTL_INT (mmu, HW_MMU_BLOCKSIZE, blockSize, CTLFLAG_RD,
|
||||
&mmuArchLibAttrs.blockSize, 0, "");
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# Makefile - makefile for building the analysis tools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01j,21jan14,wzc Fix ar missed in environment.
|
||||
# 01i,24aug11,flu CQID: WIND00295502 remove stacktrace.so libanalysistest.a for LP64.
|
||||
# 01h,15aug11,flu CQID WIND00293303
|
||||
# 01g,02aug11,jfu Create directory in adding test case for vxauto test(RQ:WIND00267114)
|
||||
# 01g,29jul11,flu Add simso and simnt for auto test building.(CQ:WIND00290406)
|
||||
# 01g,20jul11,flu create libanalysistest.a for vxtest.(RQ:WIND00267114)
|
||||
# 01f,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
# 01e,25nov10,flu Add dkms dependency.(CQ:WIND00241407)
|
||||
# 01d,24nov10,flu Skip dkms building for some OPT.(CQ:WIND00242405)
|
||||
# 01c,01nov10,pca Exclude unnecessary objects from LP64 builds
|
||||
# 01b,13may08,c_c default rule builds everything.
|
||||
# 01a,26mar08,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the Analysis Tools
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = .
|
||||
|
||||
SUPPORTED_OPTIONS_ANALYSIS_SKIP = -inet6only -inet6 -basic
|
||||
|
||||
ifeq ($(filter $(OPT), $(SUPPORTED_OPTIONS_ANALYSIS_SKIP)),)
|
||||
all: subdirs dkms
|
||||
.PHONY: all dkms
|
||||
else
|
||||
all:subdirs
|
||||
.PHONY: all
|
||||
endif
|
||||
|
||||
# The SUBDIRS variable needs to be manually defined to make sure the
|
||||
# subdirectories are built in the correct order. Normally this would be done
|
||||
# by specifying dependencies, for example:
|
||||
# coveragescope: rtilib scopeutils
|
||||
# Unfortunately the Vx make rule fragments specify the phony subdirectory goals
|
||||
# as double-colon rules (e.g., coveragescope::) which prevents other makefiles
|
||||
# from adding meaningful dependencies.
|
||||
|
||||
# Including defs.library to see VSB defines _WRS_CONFIG_SMP/LP64.
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
ifndef _WRS_CONFIG_LP64
|
||||
SUBDIRS = rtilib scopeutils memscope profile stethoscope coveragescope stacktrace
|
||||
else
|
||||
SUBDIRS = rtilib scopeutils coveragescope cafe stacktrace
|
||||
endif
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
ifeq ($(ENABLE_HEADER_GENERATION),1)
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),simlinux)
|
||||
IS_SIM_ARCH = true
|
||||
endif
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),simpc)
|
||||
IS_SIM_ARCH = true
|
||||
endif
|
||||
|
||||
ifeq ($(VX_CPU_FAMILY),simso)
|
||||
IS_SIM_ARCH = true
|
||||
endif
|
||||
|
||||
ANALYSISTEST_PATH = $(VSB_DIR)/$(VX_CPU_FAMILY)$(ARCH_OPTION_SUFFIX)/$(CPU)$(CPU_OPTION_SUFFIX)/$(TOOL_COMMON_DIR)$(LIB_DIR_TAG)$(MINOR_OPTION_SUFFIX)
|
||||
|
||||
ANALYSISTEST_OBJS = $(LIB_ROOT)/$(LIBDIRBASE)/objcoveragecomm/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objrtilib/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objscopeutils/*.o
|
||||
|
||||
ifndef _WRS_CONFIG_LP64
|
||||
ANALYSISTEST_OBJS += $(LIB_ROOT)/$(LIBDIRBASE)/objclock/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objfilter/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objquery/*.o \
|
||||
$(ANALYSISTEST_PATH)/objstacktrace/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objmemscope/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objprofile/*.o
|
||||
ifneq (true,$(IS_SIM_ARCH))
|
||||
ANALYSISTEST_OBJS += $(LIB_ROOT)/$(LIBDIRBASE)/objparam/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objpatch/*.o
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
dkms:subdirs
|
||||
$(MAKE) -C scopeutils $@
|
||||
$(MAKE) -C coveragescope $@
|
||||
ifndef _WRS_CONFIG_LP64
|
||||
$(MAKE) -C stacktrace $@
|
||||
$(MAKE) -C memscope $@
|
||||
$(MAKE) -C profile $@
|
||||
$(MAKE) -C stethoscope $@
|
||||
ifeq ($(ENABLE_HEADER_GENERATION),1)
|
||||
$(AR) -r $(ANALYSISTEST_PATH)/libanalysistest.a $(ANALYSISTEST_OBJS)
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,63 @@
|
||||
# Makefile - makefile for target/src/debug/cafe
|
||||
#
|
||||
# Copyright (c) 2011 Wind River Systems, Inc.
|
||||
#
|
||||
# The right to copy, distribute, modify or otherwise make use of this software
|
||||
# may be licensed only pursuant to the terms of an applicable Wind River
|
||||
# license agreement.
|
||||
#
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,23mar11,vhe Fixed Cafe component
|
||||
# 01a,11mar11,flu written.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This is the top level Makefile for building the cafe component during
|
||||
# GPP builds.
|
||||
#
|
||||
# Note that this file is a temporary work-waround and will be obsoleted when
|
||||
# GPP build infratstructure is fixed to build components outside $TGT_DIR,
|
||||
# for example components in $WIND_HOME/components.
|
||||
#
|
||||
|
||||
TGT_DIR = $(WIND_BASE)/target
|
||||
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
ifneq ($(wildcard $(WRVX_COMPBASE)/$(COMP_CAFE)/Makefile),)
|
||||
|
||||
default:
|
||||
$(MAKE) -C $(WRVX_COMPBASE)/$(COMP_CAFE) TOOL=$(_WRS_CONFIG_APP_TOOL) _VSB_CONFIG_ADDEDCFLAGS=$(__VSB_ADDEDCFLAGSAPP) CPU=$(CPU) VSB_DIR=$(VSB_DIR) OPT=$(OPT)
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(WRVX_COMPBASE)/$(COMP_CAFE) TOOL=$(_WRS_CONFIG_APP_TOOL) _VSB_CONFIG_ADDEDCFLAGS=$(__VSB_ADDEDCFLAGSAPP) CPU=$(CPU) VSB_DIR=$(VSB_DIR) OPT=$(OPT) clean
|
||||
|
||||
rclean:
|
||||
$(MAKE) -C $(WRVX_COMPBASE)/$(COMP_CAFE) TOOL=$(_WRS_CONFIG_APP_TOOL) _VSB_CONFIG_ADDEDCFLAGS=$(__VSB_ADDEDCFLAGSAPP) CPU=$(CPU) VSB_DIR=$(VSB_DIR) OPT=$(OPT) rclean
|
||||
|
||||
man:
|
||||
$(MAKE) -C $(WRVX_COMPBASE)/$(COMP_CAFE) TOOL=$(_WRS_CONFIG_APP_TOOL) _VSB_CONFIG_ADDEDCFLAGS=$(__VSB_ADDEDCFLAGSAPP) CPU=$(CPU) VSB_DIR=$(VSB_DIR) OPT=$(OPT) man
|
||||
|
||||
synopsis:
|
||||
$(MAKE) -C $(WRVX_COMPBASE)/$(COMP_CAFE) TOOL=$(_WRS_CONFIG_APP_TOOL) _VSB_CONFIG_ADDEDCFLAGS=$(__VSB_ADDEDCFLAGSAPP) CPU=$(CPU) VSB_DIR=$(VSB_DIR) OPT=$(OPT) synopsis
|
||||
|
||||
|
||||
release: default
|
||||
else
|
||||
# the cafe component is not present - nothing to do
|
||||
default:
|
||||
|
||||
clean:
|
||||
|
||||
rclean:
|
||||
|
||||
release:
|
||||
|
||||
endif
|
||||
|
||||
# rules that do nothing for cafe
|
||||
precomp:
|
||||
|
||||
% :
|
||||
@echo nothing to be done for target $@
|
||||
@@ -0,0 +1,36 @@
|
||||
# Makefile - makefile for coveragescope
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the coveragescope
|
||||
# TCP communication libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR = $(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ..
|
||||
|
||||
LIB_BASE_NAME = coveragecomm
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
|
||||
DKMS = $(LIB_ROOT)/$(DKMDIRBASE)/libcoveragecomm.so
|
||||
COVERAGE_OBJS = $(LIB_ROOT)/$(LIBDIRBASE)/objcoveragecomm/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objscopeutils/base64.o
|
||||
|
||||
.PHONY: dkms
|
||||
|
||||
dkms: $(DKMS)
|
||||
|
||||
$(LIB_ROOT)/$(DKMDIRBASE)/libcoveragecomm.so: $(COVERAGE_OBJS)
|
||||
$(LD_PARTIAL) $^ -o $@
|
||||
|
||||
LOCAL_CLEAN += $(DKMS)
|
||||
|
||||
# end of scopetools/coveragescope
|
||||
@@ -0,0 +1,42 @@
|
||||
# Makefile - makefile for coveragescope
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,03jun10,jpb Added _WRS_CONFIG_RTP conditional.
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the coveragescope
|
||||
# TCP communication libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR = $(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../..
|
||||
|
||||
LIB_BASE_NAME = coveragecomm
|
||||
|
||||
# Including defs.library to see if _WRS_CONFIG_xxx is defined.
|
||||
# It must be after LIB_BASE_NAME
|
||||
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
OBJS = symfind.o datasend.o coveragenet.o handlers.o coveragedata.o utils.o
|
||||
|
||||
ifdef _WRS_CONFIG_RTP
|
||||
OBJS += rtp_support.o
|
||||
endif
|
||||
|
||||
PKG_H = coveragedata.pkg.h coveragenet.pkg.h handlers.pkg.h symfind.pkg.h \
|
||||
utils.pkg.h datasend.pkg.h rtp_support.pkg.h
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
|
||||
# end of coveragescope/src
|
||||
@@ -0,0 +1,185 @@
|
||||
Design
|
||||
-----
|
||||
|
||||
I. Introduction
|
||||
------------
|
||||
|
||||
Ideas behind the design
|
||||
|
||||
1. To have a text based XML like protocol, which in its own way makes
|
||||
the protocol easier to understand.
|
||||
|
||||
Have good recovery mechanisms for lost data, and to be able to easily
|
||||
resynchronize with the target.
|
||||
|
||||
2. Not much overhead with using XML
|
||||
|
||||
3. Should be simple to add and remove to a communication protocol
|
||||
|
||||
|
||||
|
||||
II. Current design
|
||||
--------------
|
||||
|
||||
The host and target communicate with XML like commands. A Sample command
|
||||
would have a format like
|
||||
<Command name=createFile numParam=3>
|
||||
<Param fileName=hello></Param>
|
||||
<Param owner=saket></Param>
|
||||
<Param permission=755></Param>
|
||||
</Command>
|
||||
|
||||
|
||||
The receiving end would receive data over the network and keep passing it
|
||||
on to the parser. The receiving side would pre-register handler functions
|
||||
for different Commands that it would receive on the communication link.
|
||||
The parser keeps calling the registered functions as it processes data
|
||||
received on the communication link. The handler function can then extract
|
||||
the parameters and take appropriate action.
|
||||
|
||||
void handlerCreateFile(void* xmlHandle){
|
||||
char* fileName=parseParamString("fileName",xmlHandle);
|
||||
char* owner=parseParamString("owner",xmlHandle);
|
||||
char* permission=atoi(parseParamString("permission",xmlHandle));
|
||||
|
||||
touch filename;
|
||||
chown owner filename;
|
||||
chmod permission filename;
|
||||
|
||||
}
|
||||
|
||||
This makes chaging the protocol and the parameters very simple for the
|
||||
host/target.
|
||||
|
||||
|
||||
IIa. Data Structures
|
||||
|
||||
+-----------------------+
|
||||
| Number of functions |
|
||||
+-----------------------+
|
||||
| Max num of functions |
|
||||
+=======================+
|
||||
|Function name |
|
||||
|Function pointer |
|
||||
|Default parameters |
|
||||
+-----------------------+
|
||||
| .... |
|
||||
| .... |
|
||||
|_______________________|
|
||||
|
||||
|
||||
IIb. Default parameters
|
||||
|
||||
a) from the other communication end you receive
|
||||
i) function to call
|
||||
ii) parameters (remote)
|
||||
|
||||
There might be cases when you would like to pass local parameters
|
||||
to this function, for example passing the object pointer to all
|
||||
handler functions.
|
||||
|
||||
|
||||
IIc. Sending binary data
|
||||
|
||||
Binary data is sent over the XML protcol after base-64 encoding the data.
|
||||
This adds a 33% overhead to the amount of data being sent.
|
||||
|
||||
III. API
|
||||
---
|
||||
|
||||
1. To use the API you first call XMLInit(int) which returns a memory pointer.
|
||||
This pointer is the handle to the XML library
|
||||
2. Now you can register handler functions using the registerFunction call
|
||||
3. Once you have registered all your handlers you just need to keep calling the
|
||||
passing on the data you get over the network to the parser.
|
||||
|
||||
|
||||
IV. Features
|
||||
--------
|
||||
|
||||
1. Fully re-entrant
|
||||
2. Passing local parameters
|
||||
|
||||
V. Implementation notes
|
||||
--------------------
|
||||
The code in this folder serves several purposes. When used in wtx
|
||||
mode, the "CoverageLink" is a thread on the host side and uses wtx
|
||||
calls to get the arrays from the target. In TCP/IP mode the
|
||||
"CoverageLink" is a task on the target that will read and send out
|
||||
data to the host via TCP. Through coveragewtx.cxx, this code is
|
||||
also used for host side wtx calls to the target, such as for
|
||||
finding symbols or starting the TCP/IP link.
|
||||
|
||||
As the link code is different depending on whether it is target or
|
||||
host side, the code is liberally sprinkled with "#ifdef COVERAGE_WTX"
|
||||
statements.
|
||||
|
||||
|
||||
VI. AE Changes
|
||||
----------
|
||||
|
||||
The major change that was needed for the AE port is dealing with
|
||||
multiple PDs. It was decided that CoverageScope should just add
|
||||
together the results from multiple pds. This means that it needs
|
||||
to look for the arrays in every pd. So at the beginning of each
|
||||
polling cycle, CoverageScope checks to see if any pds are
|
||||
added. The host keeps a list of all the pds found and a list of
|
||||
all the array names, so the array names + pd can be added to the
|
||||
list of all arrays + pd when a new pd is found. The list of array
|
||||
names and list of pds is kept host side, in TCPDataLinkAE.java for
|
||||
tcp mode and in the CoverageDaemonInfo struct (coveragedata.c) in
|
||||
wtx mode.
|
||||
|
||||
VII. Things to do
|
||||
------------
|
||||
|
||||
1. Add verbosity
|
||||
2. Rename functions..
|
||||
3. More error checking/reporting for robustness
|
||||
4. Automated test suites
|
||||
|
||||
|
||||
VIII. Other uses
|
||||
----------
|
||||
(?) Automated test suite generator
|
||||
|
||||
|
||||
IX. Example of a basic link code
|
||||
----------------------------
|
||||
|
||||
The basic code for writing a link piece based on the XML parser
|
||||
is pretty simple. Here is an example framework.
|
||||
|
||||
link.c
|
||||
------
|
||||
....
|
||||
|
||||
Link(){
|
||||
|
||||
xmlhandle=XMLInit(10)
|
||||
sprintf(xmlParam,"<Param pCoverage=%u ></Param>",(unsigned int) pCoverage);
|
||||
registerFunction("CONNECT_CONFIRM",CoverageConnectConfirm,xmlParam,xmlHandle);
|
||||
|
||||
while (true){
|
||||
if there is no connection
|
||||
wait for connection()
|
||||
else
|
||||
read(readbuff);
|
||||
commandParse(readbuff);
|
||||
|
||||
sleep(short duration);
|
||||
}
|
||||
|
||||
|
||||
handler.c
|
||||
---------
|
||||
void CoverageConnectConfirm(void* xmlHandle){
|
||||
CoverageDaemonInfo* pCoverage= (CoverageDaemonInfo*)(atoi(parseParamStri
|
||||
ng\
|
||||
("pCoverage",xmlHandle)));
|
||||
pCoverage->connectionUp=RTI_TRUE;
|
||||
if (pCoverage->debugLevel>0)
|
||||
RtiMessage("Connection Confirmed from host side\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* coveragedata.c - Coverage data structures and constants */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
02a,10feb10,flu Remove obsolete code and change type definition for 64-bit porting.
|
||||
1.2a, jfu 27 Jul 2009 clear existing coverage data via
|
||||
RESET_ALL_COVERAGE_ARRAYS/RESET_ALL_COVERAGE_ARRAYS
|
||||
commands for requirement 170416
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
1.1a, pca 30 May 2002 ported to rtilib 4.2
|
||||
1.0, sks 19 Nov 2001 created
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Coverage data structures and constants.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
|
||||
#ifdef RTI_WIN32
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
# include <vxWorks.h>
|
||||
# include <vsbConfig.h>
|
||||
# include <private/kernelBaseLibP.h>
|
||||
# include <private/taskLibP.h>
|
||||
# include <private/taskMemLibP.h>
|
||||
|
||||
# include <rtilib/vxVersions.h>
|
||||
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
#endif
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
/*Begin Peer block*/
|
||||
#pragma begin_Peer
|
||||
#include <stdio.h>
|
||||
|
||||
#include <rtilib/rti_tcp.h>
|
||||
#include <rtilib/rti_endian.h>
|
||||
#include <rtilib/rti_time.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/rti_osapi.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#include <eventsxml.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
#define COVERAGE_LINK_PRIORITY 3
|
||||
#else
|
||||
#define COVERAGE_LINK_PRIORITY 200
|
||||
#endif
|
||||
|
||||
#define PACKET_START 1
|
||||
#define PACKET_INIT 2
|
||||
#define PACKET_DATA 3
|
||||
|
||||
#define LINK_STATUS_INIT 0x00
|
||||
#define LINK_STATUS_CONNECTING 0x01
|
||||
#define LINK_STATUS_CONNECTED 0x02
|
||||
#define LINK_STATUS_COLLECTING 0x03
|
||||
#define LINK_STATUS_HAVEARRAY 0x10
|
||||
#define LINK_MASK_HAVEARRAY 0xf0
|
||||
|
||||
#define GET_LINK_STATUS(a) ((a)&(~LINK_MASK_HAVEARRAY))
|
||||
#define HAVE_ARRAY(a) ((a)&(LINK_MASK_HAVEARRAY))
|
||||
#define SET_LINK_STATUS(a,b) ((a)=HAVE_ARRAY(a)|(b))
|
||||
|
||||
#define DEFAULT_SLEEP_SEC 0
|
||||
#define DEFAULT_SLEEP_NSEC 200000000
|
||||
|
||||
#define TCP_SEND_SIZE 1400
|
||||
#define COVERAGE_XML_MAX_CALLBACKS 16
|
||||
|
||||
#define EXIT_SIGNAL_FALSE 0
|
||||
#define EXIT_SIGNAL_TRUE 1
|
||||
#define EXIT_SIGNAL_SHUTDOWN 2
|
||||
|
||||
#define LINK_THREAD_NOTSTARTED 0
|
||||
#define LINK_THREAD_RUNNING 1
|
||||
#define LINK_THREAD_EXITING 2
|
||||
/*
|
||||
* ??? Can LINK_MAX_READSIZE handle very huge XML commands
|
||||
* which might overflow cmdBuff
|
||||
*
|
||||
* There's no way we can parse if a single xml command overflows
|
||||
* cmdbuff
|
||||
*/
|
||||
|
||||
/*
|
||||
* Assuming ethernet frame size of 1500, keep the WRITEBUFF size to be 1280
|
||||
*/
|
||||
#define XML_CMDSIZE 2048
|
||||
#define LINK_READSIZE 1024
|
||||
#define LINK_WRITESIZE XML_CMDSIZE
|
||||
|
||||
/* Maximum length of a variable name */
|
||||
#define CVG_MAX_VARLENGTH 256
|
||||
#define CVG_MAX_STRLEN 128
|
||||
|
||||
/*If XML_DATASIZE bytes on base64 encoding willl
|
||||
* occupy 1024 bytes
|
||||
*/
|
||||
#define XML_ENCODEDSIZE 1024
|
||||
#define XML_DATASIZE 764
|
||||
|
||||
/*
|
||||
* The target can return to the host a string return value
|
||||
* for example a reason string like file not found
|
||||
*/
|
||||
#define MAX_RETURN_SIZE 512
|
||||
|
||||
#define MAX_SHM_REGION 32
|
||||
|
||||
#define COVERAGE_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define CoverageV0Warning printf
|
||||
#define CoverageV1Warning(a) if (a>=1) CoverageV0Warning
|
||||
#define CoverageV2Warning(a) if (a>=2) CoverageV0Warning
|
||||
#define CoverageV3Warning(a) if (a>=3) CoverageV0Warning
|
||||
#define CoverageV4Warning(a) if (a>=4) CoverageV0Warning
|
||||
|
||||
/*
|
||||
* Data type used by the coverage arrays
|
||||
*/
|
||||
typedef int CVGARRAYTYPE;
|
||||
|
||||
/*** Information for wtx ***/
|
||||
|
||||
/*** Information about the link task running on the target or host ***/
|
||||
typedef struct {
|
||||
INT8 linkStatus; /*Status of link thread*/
|
||||
INT8 connStatus; /*Status of network connection with host*/
|
||||
INT8 exitSignal; /*signals exit condition to daemon*/
|
||||
INT8 threadStatus; /*Status of the link thread*/
|
||||
RTIBool connectionUp; /*Flag indicating connection status*/
|
||||
RTIThreadId linkThreadId; /*thread identifier*/
|
||||
RTITcp* plinkTcp; /*pointer to tcp object*/
|
||||
INT32 debugLevel; /*Debugging level*/
|
||||
void* xmlHandle; /*Handle to the xml interpreter*/
|
||||
CVGARRAYTYPE** pCoverageArray; /*Pointer to coverage arrays*/
|
||||
char** coverageArrayNames; /*Names of arrays being covered*/
|
||||
RTP_ID* coverageArrayPdId; /*PdIds of arrays being covered */
|
||||
INT32 numArrays; /*Number of coverage arrays*/
|
||||
RTINtpTime coverageDelay; /*Delay - set by SetPollRate */
|
||||
char encodedData[XML_ENCODEDSIZE]; /*Buffer for keeping base64EncodedData*/
|
||||
char writeBuff[LINK_WRITESIZE];/*Data buffer for sending via TCP/IP*/
|
||||
char readBuff[LINK_READSIZE]; /*Data buffer for reading*/
|
||||
char cmdBuff[4*LINK_READSIZE]; /*Buffer to store commands for parser*/
|
||||
char returnMsg[MAX_RETURN_SIZE];
|
||||
|
||||
}CoverageDaemonInfo;
|
||||
|
||||
|
||||
#pragma end_Peer
|
||||
/*End Peer Block*/
|
||||
@@ -0,0 +1,143 @@
|
||||
/* coveragedata.pkg.h - built from: coveragedata.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef coveragedata_pkg_h
|
||||
#define coveragedata_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <rtilib/rti_tcp.h>
|
||||
#include <rtilib/rti_endian.h>
|
||||
#include <rtilib/rti_time.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/rti_osapi.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#include <eventsxml.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
#define COVERAGE_LINK_PRIORITY 3
|
||||
#else
|
||||
#define COVERAGE_LINK_PRIORITY 200
|
||||
#endif
|
||||
|
||||
#define PACKET_START 1
|
||||
#define PACKET_INIT 2
|
||||
#define PACKET_DATA 3
|
||||
|
||||
#define LINK_STATUS_INIT 0x00
|
||||
#define LINK_STATUS_CONNECTING 0x01
|
||||
#define LINK_STATUS_CONNECTED 0x02
|
||||
#define LINK_STATUS_COLLECTING 0x03
|
||||
#define LINK_STATUS_HAVEARRAY 0x10
|
||||
#define LINK_MASK_HAVEARRAY 0xf0
|
||||
|
||||
#define GET_LINK_STATUS(a) ((a)&(~LINK_MASK_HAVEARRAY))
|
||||
#define HAVE_ARRAY(a) ((a)&(LINK_MASK_HAVEARRAY))
|
||||
#define SET_LINK_STATUS(a,b) ((a)=HAVE_ARRAY(a)|(b))
|
||||
|
||||
#define DEFAULT_SLEEP_SEC 0
|
||||
#define DEFAULT_SLEEP_NSEC 200000000
|
||||
|
||||
#define TCP_SEND_SIZE 1400
|
||||
#define COVERAGE_XML_MAX_CALLBACKS 16
|
||||
|
||||
#define EXIT_SIGNAL_FALSE 0
|
||||
#define EXIT_SIGNAL_TRUE 1
|
||||
#define EXIT_SIGNAL_SHUTDOWN 2
|
||||
|
||||
#define LINK_THREAD_NOTSTARTED 0
|
||||
#define LINK_THREAD_RUNNING 1
|
||||
#define LINK_THREAD_EXITING 2
|
||||
/*
|
||||
* ??? Can LINK_MAX_READSIZE handle very huge XML commands
|
||||
* which might overflow cmdBuff
|
||||
*
|
||||
* There's no way we can parse if a single xml command overflows
|
||||
* cmdbuff
|
||||
*/
|
||||
|
||||
/*
|
||||
* Assuming ethernet frame size of 1500, keep the WRITEBUFF size to be 1280
|
||||
*/
|
||||
#define XML_CMDSIZE 2048
|
||||
#define LINK_READSIZE 1024
|
||||
#define LINK_WRITESIZE XML_CMDSIZE
|
||||
|
||||
/* Maximum length of a variable name */
|
||||
#define CVG_MAX_VARLENGTH 256
|
||||
#define CVG_MAX_STRLEN 128
|
||||
|
||||
/*If XML_DATASIZE bytes on base64 encoding willl
|
||||
* occupy 1024 bytes
|
||||
*/
|
||||
#define XML_ENCODEDSIZE 1024
|
||||
#define XML_DATASIZE 764
|
||||
|
||||
/*
|
||||
* The target can return to the host a string return value
|
||||
* for example a reason string like file not found
|
||||
*/
|
||||
#define MAX_RETURN_SIZE 512
|
||||
|
||||
#define MAX_SHM_REGION 32
|
||||
|
||||
#define COVERAGE_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define CoverageV0Warning printf
|
||||
#define CoverageV1Warning(a) if (a>=1) CoverageV0Warning
|
||||
#define CoverageV2Warning(a) if (a>=2) CoverageV0Warning
|
||||
#define CoverageV3Warning(a) if (a>=3) CoverageV0Warning
|
||||
#define CoverageV4Warning(a) if (a>=4) CoverageV0Warning
|
||||
|
||||
/*
|
||||
* Data type used by the coverage arrays
|
||||
*/
|
||||
typedef int CVGARRAYTYPE;
|
||||
|
||||
/*** Information for wtx ***/
|
||||
|
||||
/*** Information about the link task running on the target or host ***/
|
||||
typedef struct {
|
||||
INT8 linkStatus; /*Status of link thread*/
|
||||
INT8 connStatus; /*Status of network connection with host*/
|
||||
INT8 exitSignal; /*signals exit condition to daemon*/
|
||||
INT8 threadStatus; /*Status of the link thread*/
|
||||
RTIBool connectionUp; /*Flag indicating connection status*/
|
||||
RTIThreadId linkThreadId; /*thread identifier*/
|
||||
RTITcp* plinkTcp; /*pointer to tcp object*/
|
||||
INT32 debugLevel; /*Debugging level*/
|
||||
void* xmlHandle; /*Handle to the xml interpreter*/
|
||||
CVGARRAYTYPE** pCoverageArray; /*Pointer to coverage arrays*/
|
||||
char** coverageArrayNames; /*Names of arrays being covered*/
|
||||
RTP_ID* coverageArrayPdId; /*PdIds of arrays being covered */
|
||||
INT32 numArrays; /*Number of coverage arrays*/
|
||||
RTINtpTime coverageDelay; /*Delay - set by SetPollRate */
|
||||
char encodedData[XML_ENCODEDSIZE]; /*Buffer for keeping base64EncodedData*/
|
||||
char writeBuff[LINK_WRITESIZE];/*Data buffer for sending via TCP/IP*/
|
||||
char readBuff[LINK_READSIZE]; /*Data buffer for reading*/
|
||||
char cmdBuff[4*LINK_READSIZE]; /*Buffer to store commands for parser*/
|
||||
char returnMsg[MAX_RETURN_SIZE];
|
||||
|
||||
}CoverageDaemonInfo;
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* coveragedata_pkg_h */
|
||||
@@ -0,0 +1,139 @@
|
||||
/* coveragenet.c - Coverage data send */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01c,01dec10,flu Change type defination of size.(CQ:WIND00240495)
|
||||
01b,10feb10,flu Change interface definition for 64-bit porting.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
1.1a, pca 30 May 2002 ported to rtilib 4.2
|
||||
1.0, sks 19 Nov 2001 created
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Coverage data send
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include "coveragedata.pkg.h"
|
||||
|
||||
/* Ignore SIGPIPE signal while writing */
|
||||
#ifdef RTI_UNIX
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
Peer
|
||||
size_t CoverageSafeWrite( RTITcp *tcp, void *pkt, size_t size )
|
||||
{
|
||||
size_t retVal;
|
||||
void (*pipeDefFunc)();
|
||||
|
||||
pipeDefFunc = (void (*)())signal(SIGPIPE, SIG_IGN);
|
||||
retVal = tcp->Writen(tcp, pkt, size);
|
||||
signal(SIGPIPE, (void (*)(int))pipeDefFunc);
|
||||
return(retVal);
|
||||
}
|
||||
#else
|
||||
|
||||
/* defines */
|
||||
|
||||
#pragma begin_Peer
|
||||
#define CoverageSafeWrite( tcp, pkt, size ) tcp->Writen(tcp, pkt, size)
|
||||
#pragma end_Peer
|
||||
#endif
|
||||
|
||||
/* Sends data using TCP object - based on non-blocking socket */
|
||||
/* retVal = -3 - exit condition detected
|
||||
* retVal = -2 - unknown TCP error
|
||||
* retVal = -1 - size = 0
|
||||
* retVal = 0 - no errors; data sent
|
||||
*
|
||||
* We use exponential backoff mechanism if no data gets sent, this
|
||||
* might be due to the fact that network queue is too full
|
||||
* For every 10 consecutive such calls we double the sleep time starting
|
||||
* at 10 us
|
||||
*/
|
||||
Peer
|
||||
int CoverageDataSend( CoverageDaemonInfo* pCoverage, char *pkt, size_t size)
|
||||
{
|
||||
int retVal = -1;
|
||||
ssize_t bytesSent = 0;
|
||||
|
||||
RTINtpTime sleepTime; /*adaptive sleep time*/
|
||||
int countSendZero=0; /*number of times 0 bytes were sent*/
|
||||
int tenMicroSec=10000; /*10us in terms of ns*/
|
||||
int adaptiveFactor=0;
|
||||
|
||||
RtiNtpTimePackFromNanosec(sleepTime, 0, 0);
|
||||
|
||||
if( size == 0 )
|
||||
{
|
||||
return(retVal);
|
||||
}
|
||||
|
||||
while(RTI_TRUE && pCoverage->exitSignal==EXIT_SIGNAL_FALSE)
|
||||
{
|
||||
if((bytesSent = CoverageSafeWrite(pCoverage->plinkTcp, pkt, size))
|
||||
== size)
|
||||
{
|
||||
retVal = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if(bytesSent < 0)
|
||||
{
|
||||
/* write error */
|
||||
if(RtiNetioErrnoGet() != EWOULDBLOCK)
|
||||
{
|
||||
/* unknown error */
|
||||
retVal = -2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(bytesSent == 0)
|
||||
{
|
||||
countSendZero++;
|
||||
if (pCoverage->debugLevel>3)
|
||||
printf("CoverageScopeDataSend: 0 bytes sent!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* modify size and pointer for next try */
|
||||
size -= bytesSent;
|
||||
pkt += bytesSent;
|
||||
countSendZero=0;
|
||||
}
|
||||
/*Without this sleep the task starts to hog CPU when send fails*/
|
||||
adaptiveFactor=(countSendZero/10);
|
||||
if (adaptiveFactor != 0) {
|
||||
unsigned long sec, nsec;
|
||||
RtiNtpTimeUnpackToNanosec(sec, nsec, sleepTime);
|
||||
if (nsec < 2000*tenMicroSec) {
|
||||
RtiNtpTimePackFromNanosec(sleepTime, 0,
|
||||
(1<<adaptiveFactor)*tenMicroSec);
|
||||
}
|
||||
if (pCoverage->debugLevel>3) {
|
||||
unsigned long sec, nsec;
|
||||
RtiNtpTimeUnpackToNanosec(sec, nsec, sleepTime);
|
||||
printf("Sleeping for :%lu nsecs\n", nsec);
|
||||
}
|
||||
RtiThreadSleep(&sleepTime);
|
||||
}
|
||||
}
|
||||
return (retVal);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* coveragenet.pkg.h - built from: coveragenet.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef coveragenet_pkg_h
|
||||
#define coveragenet_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern size_t CoverageSafeWrite( RTITcp *tcp, void *pkt, size_t size );
|
||||
|
||||
|
||||
#define CoverageSafeWrite( tcp, pkt, size ) tcp->Writen(tcp, pkt, size)
|
||||
|
||||
|
||||
extern int CoverageDataSend( CoverageDaemonInfo* pCoverage, char *pkt, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* coveragenet_pkg_h */
|
||||
@@ -0,0 +1,650 @@
|
||||
/* datasend.c - Code Coverage Lib */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010, 2012 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01f,08aug12,wzc WIND00357415 - Remove building warnings.
|
||||
01e,18jan12,wzc WIND00266126 - add a taskDelay without rtp support.
|
||||
01d,07jun10,jpb Added _WRS_CONFIG_RTP conditionals.
|
||||
01c,10feb10,flu Remove obsolete code for 64-bit porting.
|
||||
01b,24sep09,flu For defect 183531, remove Tcp port reuse
|
||||
01a,27jul09,jfu Clear existing coverage data via
|
||||
RESET_ALL_COVERAGE_ARRAYS/RESET_ALL_COVERAGE_ARRAYS
|
||||
commands for requirement 170416
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
/* $Id: */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Code Coverage Lib
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h> /* _WRS_CONFIG_RTP */
|
||||
#include <rtilib/makeheader.h>
|
||||
#include "handlers.pkg.h"
|
||||
#include "coveragenet.pkg.h"
|
||||
#include "coveragedata.pkg.h"
|
||||
#include "datasend.pkg.h"
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
# include <sysLib.h>
|
||||
# include "rtp_support.pkg.h"
|
||||
#endif
|
||||
|
||||
//int CoverageTcpPort = 3333;
|
||||
Public unsigned int CODECOVERAGE_LIB_VERSION = 0x00020601;
|
||||
/*
|
||||
* Global CoverageDaemonInfo variable - Needed to Call CoverageShutDown
|
||||
* externally. This variable means that we can't run multiple CoverageLinks on
|
||||
* the same machine. If we ever want to do that, we would need a global array
|
||||
* of CoverageDaemonInfo*, and an index into the array. Every instance of
|
||||
* CoverageLink would have a unique index, this index would also be used to
|
||||
* get a unique port number.
|
||||
*/
|
||||
|
||||
Peer
|
||||
CoverageDaemonInfo* CoverageInfo = 0;
|
||||
|
||||
|
||||
/*--------------------Static function prototypes-------------------------*/
|
||||
|
||||
static void coverageThreadOptionsSet( int inputPrio, int normalPrio, \
|
||||
int *nativePrio,
|
||||
RTIThreadOptions *pThreadOptions );
|
||||
|
||||
/*--------------------Coverage Startup routines--------------------------*/
|
||||
|
||||
Public
|
||||
|
||||
int CodeCoverAgentVersionGet(void)
|
||||
{
|
||||
return CODECOVERAGE_LIB_VERSION;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* Extended api for starting Coverage server, allows user to
|
||||
* specify more parameters
|
||||
*/
|
||||
int CoverageInitServerEx(int verbosity, int priority, int tcpPortNumber)
|
||||
{
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
|
||||
/*Init the server to get data structures allocated*/
|
||||
pCoverage = CoverageInit(verbosity);
|
||||
|
||||
if (pCoverage == 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* If server started succesfully then set CoverageInfo
|
||||
* to the data structure */
|
||||
return CoverageInitServerInternal(pCoverage, priority, tcpPortNumber);
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* Internal call to Coverage Init server.
|
||||
*/
|
||||
int CoverageInitServerInternal(CoverageDaemonInfo* pCoverage, int priority, int tcpPortNumber)
|
||||
{
|
||||
RTIThreadOptions linkOptions;
|
||||
int nativeLinkPriority = 0;
|
||||
int port;
|
||||
|
||||
if (!RtiNetioInit())
|
||||
{
|
||||
printf("CoverageInitServer:Error initializing netio routines\n");
|
||||
free(pCoverage);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if ((pCoverage->plinkTcp=RtiTcpNew(RTI_TCP_SERVER, tcpPortNumber, RTI_TCP_NOACTION))
|
||||
== NULL)
|
||||
{
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("CoverageInitServer:Error TcpNew failed\n");
|
||||
printf("Coverage server already running\n");
|
||||
free(pCoverage);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* does not block while listening for a connection */
|
||||
pCoverage->plinkTcp->ListenBlockingSet(pCoverage->plinkTcp,
|
||||
RTI_NETIO_NONBLOCKING);
|
||||
|
||||
/* does not block while reading/writing from/to socket */
|
||||
pCoverage->plinkTcp->DataBlockingSet(pCoverage->plinkTcp, RTI_NETIO_NONBLOCKING);
|
||||
|
||||
port = pCoverage->plinkTcp->PortGet(pCoverage->plinkTcp);
|
||||
/*Start the link daemon*/
|
||||
coverageThreadOptionsSet(-1,priority,&nativeLinkPriority,&linkOptions);
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Starting Coverage Link priority %d\n Waiting for "
|
||||
"connection on port %d\n", nativeLinkPriority, port);
|
||||
pCoverage->linkThreadId=RtiThreadCreate("CoverageLink",nativeLinkPriority,
|
||||
linkOptions, 12*1024,
|
||||
(RTIThreadStartRtn)CoverageLink,
|
||||
(void*)pCoverage);
|
||||
pCoverage->threadStatus=LINK_THREAD_RUNNING;
|
||||
|
||||
/* assign pCoverage to global CoverageInfo variable */
|
||||
CoverageInfo=pCoverage;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* CoverageInit - Initialize data structures for Coverage
|
||||
*/
|
||||
CoverageDaemonInfo * CoverageInit(int verbosity)
|
||||
{
|
||||
CoverageDaemonInfo* cInfo;
|
||||
cInfo=(CoverageDaemonInfo*)malloc(sizeof(CoverageDaemonInfo));
|
||||
if (0 == cInfo) {
|
||||
printf("Out of memory initializing the Coverage daemon.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cInfo->linkStatus = LINK_STATUS_INIT;
|
||||
cInfo->exitSignal = EXIT_SIGNAL_FALSE;
|
||||
cInfo->connectionUp = RTI_FALSE;
|
||||
cInfo->threadStatus = LINK_THREAD_NOTSTARTED;
|
||||
cInfo->debugLevel = verbosity;
|
||||
cInfo->pCoverageArray = 0;
|
||||
cInfo->coverageArrayNames = 0;
|
||||
cInfo->numArrays = 0;
|
||||
|
||||
RtiNtpTimePackFromNanosec(cInfo->coverageDelay,
|
||||
DEFAULT_SLEEP_SEC,
|
||||
DEFAULT_SLEEP_NSEC);
|
||||
|
||||
return cInfo;
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* return the link status
|
||||
*/
|
||||
int getLinkStatus(void)
|
||||
{
|
||||
if (CoverageInfo!=NULL)
|
||||
{
|
||||
return(GET_LINK_STATUS(CoverageInfo->linkStatus));
|
||||
}
|
||||
else
|
||||
return LINK_STATUS_INIT;
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* return status indicating if we have the arrays
|
||||
*/
|
||||
int getArrayFoundStatus(void)
|
||||
{
|
||||
if (CoverageInfo!=NULL)
|
||||
{
|
||||
return(HAVE_ARRAY(CoverageInfo->linkStatus));
|
||||
}
|
||||
else
|
||||
return LINK_STATUS_INIT;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------Coverage Shutdown routines--------------------------*/
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* Shutdown Coverage link- Internal Shutdown routine
|
||||
* Parameters - pointer to CoverageDaemonInfo
|
||||
*/
|
||||
int CoverageShutDownInternal(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
/*CoverageDaemonInfo* pCoverage=(CoverageDaemonInfo*)handle;*/
|
||||
RTINtpTime time;
|
||||
|
||||
if (pCoverage == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pCoverage->exitSignal=EXIT_SIGNAL_SHUTDOWN;
|
||||
|
||||
|
||||
/*Sleep for a while to let the thread close down*/
|
||||
// TD: use a more deterministic way of synchronizing the threads.
|
||||
// Note that this function is called in two ways, either from the
|
||||
// CoverageLink thread to clean up after itself, or via the wdb agent
|
||||
// only in the latter case do we actually want to wait for the thread
|
||||
// to exit...
|
||||
RtiNtpTimePackFromNanosec(time, 0, 3*DEFAULT_SLEEP_NSEC);
|
||||
|
||||
if (pCoverage->debugLevel>2)
|
||||
printf("ThreadStatus:%d\n",pCoverage->threadStatus);
|
||||
|
||||
/*Clean up memory keeping track of Coverage tag arrays*/
|
||||
CoverageClearArrayInfo(pCoverage);
|
||||
|
||||
/*XML cleanup*/
|
||||
if (pCoverage->debugLevel>2)
|
||||
{
|
||||
printf("Cleared array info\n");
|
||||
}
|
||||
XMLClose(pCoverage->xmlHandle);
|
||||
if (pCoverage->debugLevel>2)
|
||||
{
|
||||
printf("Shut down XML parser\n");
|
||||
}
|
||||
|
||||
/*Close TCP/IP*/
|
||||
if (pCoverage->plinkTcp!=NULL)
|
||||
{
|
||||
pCoverage->plinkTcp->Close(pCoverage->plinkTcp);
|
||||
RtiTcpDelete(pCoverage->plinkTcp);
|
||||
}
|
||||
if (pCoverage->debugLevel>2)
|
||||
{
|
||||
printf("Closed TCP link\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* ShutDown the Coverage Server -- Clear thread data structures
|
||||
* and free CoverageDaemonInfo data
|
||||
*/
|
||||
void CoverageShutDownServer(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
/*Delete CoverageLink Thread*/
|
||||
RtiThreadIdDelete(pCoverage->linkThreadId);
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("ShutDown Coveragelink done...\n");
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* External Call for CoverageShutDown, uses the global CoverageInfo
|
||||
*/
|
||||
int CoverageShutDown(void)
|
||||
{
|
||||
if (CoverageInfo!=NULL)
|
||||
{
|
||||
CoverageInfo->exitSignal = EXIT_SIGNAL_TRUE;
|
||||
}
|
||||
else
|
||||
printf("Coverage Server not running!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------Coverage Utility Calls ------------------------*/
|
||||
|
||||
Public
|
||||
/**
|
||||
* Call to set verbosity of the CoverageLink thread
|
||||
*/
|
||||
void CoverageSetVerbosity(int verbosity)
|
||||
{
|
||||
if (CoverageInfo!=NULL)
|
||||
CoverageInfo->debugLevel=verbosity;
|
||||
}
|
||||
|
||||
/*
|
||||
* coverageThreadOptionsSet -- Sets options for the CoverageLinkThread, sets
|
||||
*/
|
||||
Private
|
||||
void coverageThreadOptionsSet( int inputPrio, int normalPrio, int *nativePrio,
|
||||
RTIThreadOptions *pThreadOptions )
|
||||
{
|
||||
RTISystemThreadInfo sti;
|
||||
|
||||
*pThreadOptions = (RTIThreadOptions) (RTI_THREAD_STDIO |
|
||||
RTI_THREAD_FLOATING_POINT);
|
||||
|
||||
/* use realtime priority if the OS supports it */
|
||||
if (RTI_TRUE == RtiSystemThreadInfoGet(&sti)) {
|
||||
if(sti.realtimeEnabled) {
|
||||
*pThreadOptions = (RTIThreadOptions) ((*pThreadOptions) |
|
||||
RTI_THREAD_REALTIME_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
/* choose the right priority for the OS */
|
||||
if(inputPrio <= 0)
|
||||
{
|
||||
*pThreadOptions = (RTIThreadOptions) ((*pThreadOptions) |
|
||||
RTI_THREAD_PRIORITY_ENFORCE);
|
||||
#ifdef RTI_VXWORKS
|
||||
*nativePrio = normalPrio;
|
||||
#else
|
||||
*nativePrio = RtiThreadNativePriorityGet((*pThreadOptions), normalPrio);
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RTI_VXWORKS
|
||||
*nativePrio = normalPrio;
|
||||
#else
|
||||
*nativePrio = inputPrio;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* size of buffer used for common event parameter string */
|
||||
#define PARAM_BUFFER_SIZE (128)
|
||||
|
||||
private
|
||||
RTIBool registerForCommands(void * xmlHandle,
|
||||
const CoverageDaemonInfo * const pCoverage)
|
||||
{
|
||||
char xmlParam[PARAM_BUFFER_SIZE]; /*parameter to functions registered to xml interperter*/
|
||||
|
||||
/* Register callbacks for XML commands*/
|
||||
snprintf(xmlParam, PARAM_BUFFER_SIZE, "<Param pCoverage=%lu ></Param>",
|
||||
(unsigned long) pCoverage);
|
||||
|
||||
if (RTI_FALSE == registerFunction("ADD_COVERAGE_ARRAYS_ADDRS",
|
||||
CoverageAddArraysAddrs,xmlParam,
|
||||
xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
printf("Failed to register for ADD_COVERAGE_ARRAYS_ADDRS callback\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerFunction("CLEAR_COVERAGE_ARRAY_INFO",
|
||||
CoverageClearAllArrayInfo,xmlParam,
|
||||
xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerFunction("CONNECT_CONFIRM",
|
||||
CoverageConnectConfirm, xmlParam,
|
||||
xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerFunction("SEND_ALL_ARRAYS",
|
||||
CoverageSendAllCoverageArrays, xmlParam,
|
||||
xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerFunction("LINK_SHUTDOWN", CoverageLinkShutDown,
|
||||
xmlParam, xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerFunction("RESET_ALL_COVERAGE_ARRAYS",
|
||||
CoverageResetAllArrays, xmlParam,
|
||||
xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerFunction("RESET_COVERAGE_ARRAYS",
|
||||
CoverageResetArrays, xmlParam,
|
||||
xmlHandle))
|
||||
{
|
||||
printf("CoverageLink: Failed to initialize message handler (%u)\n",
|
||||
__LINE__);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
* Main function that runs as CoverageLink thread on the target
|
||||
*/
|
||||
int CoverageLink(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
int targetEndian;
|
||||
RTITcp* tcp;
|
||||
RTINtpTime time;
|
||||
RTITcpConnectStatus connectionStatus;
|
||||
size_t readLength;
|
||||
unsigned int startPosition = 0;
|
||||
int status;
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
/* the delay method we use for RTP-capable targets doesn't take an RTINtpTime object,
|
||||
so we convert it to system ticks here. */
|
||||
const int loopDelay = sysClkRateGet() * DEFAULT_SLEEP_SEC
|
||||
+ (DEFAULT_SLEEP_NSEC / (RTI_TIME_NSEC_PER_SEC / sysClkRateGet()));
|
||||
#endif
|
||||
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Starting Coverage link \n");
|
||||
/* Initialise the xml interperter*/
|
||||
pCoverage->xmlHandle = XMLInit(COVERAGE_XML_MAX_CALLBACKS);
|
||||
if (0 == pCoverage->xmlHandle) {
|
||||
pCoverage->threadStatus=LINK_THREAD_EXITING;
|
||||
CoverageShutDownInternal(pCoverage);
|
||||
CoverageShutDownServer(pCoverage);
|
||||
free(pCoverage);
|
||||
CoverageInfo=NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (RTI_FALSE == registerForCommands(pCoverage->xmlHandle, pCoverage)) {
|
||||
pCoverage->threadStatus = LINK_THREAD_EXITING;
|
||||
CoverageShutDownInternal(pCoverage);
|
||||
CoverageShutDownServer(pCoverage);
|
||||
free(pCoverage);
|
||||
CoverageInfo = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Registered xml interpreter\n");
|
||||
/*Get target endianness for informing the host*/
|
||||
|
||||
targetEndian = RtiEndianGet();
|
||||
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
CoverageInitRtpSupport();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
tcp = pCoverage->plinkTcp;
|
||||
connectionStatus = RTI_TCP_CONNECT_INPROGRESS;
|
||||
pCoverage->linkStatus=LINK_STATUS_CONNECTING;
|
||||
while(pCoverage->exitSignal == EXIT_SIGNAL_FALSE)
|
||||
{
|
||||
/* blocks till it connects to host; also checks for exit condition */
|
||||
/* initialize vars */
|
||||
switch (pCoverage->linkStatus &(~LINK_MASK_HAVEARRAY))
|
||||
{
|
||||
case LINK_STATUS_CONNECTING:
|
||||
while(connectionStatus == RTI_TCP_CONNECT_INPROGRESS &&
|
||||
pCoverage->exitSignal==EXIT_SIGNAL_FALSE)
|
||||
{
|
||||
if (tcp != 0)
|
||||
connectionStatus = tcp->Connect(tcp, 0);
|
||||
/* sleep 200ms between status checks */
|
||||
if (pCoverage->debugLevel>3)
|
||||
printf("Waiting for connection\n");
|
||||
RtiNtpTimePackFromNanosec(time, 0,
|
||||
DEFAULT_SLEEP_NSEC);
|
||||
(void) RtiThreadSleep(&time);
|
||||
}
|
||||
|
||||
if (pCoverage->exitSignal)
|
||||
{
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Received exit signal...exiting from the link thread\n");
|
||||
pCoverage->threadStatus=LINK_THREAD_EXITING;
|
||||
|
||||
/* exit the link thread if exitSignal is EXIT_SIGNAL_TRUE, otherwise
|
||||
just exit */
|
||||
if (pCoverage->exitSignal!=EXIT_SIGNAL_SHUTDOWN)
|
||||
{
|
||||
CoverageShutDownInternal(pCoverage);
|
||||
CoverageShutDownServer(pCoverage);
|
||||
free(pCoverage);
|
||||
CoverageInfo=NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* shutdown daemon if connect had failed*/
|
||||
if(connectionStatus != RTI_TCP_CONNECT_OK)
|
||||
{
|
||||
printf("Link: Failed to connect!\n Exiting...\n");
|
||||
pCoverage->threadStatus=LINK_THREAD_EXITING;
|
||||
|
||||
/* exit the link thread if exitSignal is EXIT_SIGNAL_TRUE, otherwise
|
||||
just exit */
|
||||
if (pCoverage->exitSignal!=EXIT_SIGNAL_SHUTDOWN)
|
||||
{
|
||||
CoverageShutDownInternal(pCoverage);
|
||||
CoverageShutDownServer(pCoverage);
|
||||
free(pCoverage);
|
||||
CoverageInfo=NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pCoverage->debugLevel>2)
|
||||
{
|
||||
printf("Link: Connection up!:\n");
|
||||
}
|
||||
pCoverage->linkStatus=LINK_STATUS_CONNECTED;
|
||||
/* send CONNECT confirm to client*/
|
||||
if (!pCoverage->connectionUp)
|
||||
{
|
||||
const int size = snprintf(pCoverage->writeBuff, LINK_WRITESIZE,
|
||||
"<Command name=\"CONNECT\" numparam=\"1\">\n"
|
||||
"<Param endian=\"%d\"></Param>\n"
|
||||
"<Param buffer=\"%d\"></Param>\n"
|
||||
"</Command>\n",targetEndian,
|
||||
(int)sizeof(pCoverage->cmdBuff));
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("Sending over the network:%s\n",pCoverage->writeBuff);
|
||||
if((status = CoverageDataSend(pCoverage,pCoverage->writeBuff,
|
||||
size)) < 0)
|
||||
{
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("Link: Error #%d: Error sending data!\n", status);
|
||||
pCoverage->linkStatus= LINK_STATUS_CONNECTING;
|
||||
}
|
||||
|
||||
/* ???
|
||||
else {
|
||||
pCoverage->connectionUp=RTI_TRUE;
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
}/*End switch*/
|
||||
|
||||
/*Read data from the network and process it*/
|
||||
memset(pCoverage->readBuff,0,LINK_READSIZE);
|
||||
readLength=tcp->Read(tcp,pCoverage->readBuff,LINK_READSIZE);
|
||||
if(readLength == (size_t)RTI_NETIO_ERROR)
|
||||
{
|
||||
if (pCoverage->debugLevel>1)
|
||||
{
|
||||
printf("CoverageLink: Error while reading!\n");
|
||||
}
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("Readlength:%d! Exiting...\n",readLength);
|
||||
|
||||
pCoverage->exitSignal = EXIT_SIGNAL_TRUE;
|
||||
}
|
||||
else {
|
||||
if (readLength>0)
|
||||
{
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("***************Read from client:%s\n",
|
||||
pCoverage->readBuff);
|
||||
}
|
||||
else {
|
||||
if (pCoverage->debugLevel>4)
|
||||
printf("Readlength:%d",readLength);
|
||||
}
|
||||
|
||||
if (pCoverage->debugLevel>3)
|
||||
printf("Calling CommandParse\n");
|
||||
commandParse(pCoverage->cmdBuff, pCoverage->readBuff,
|
||||
(unsigned int)readLength,
|
||||
&startPosition, pCoverage->xmlHandle);
|
||||
}
|
||||
|
||||
/*Give up the CPU*/
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
CoverageWaitForRTPs((unsigned int) loopDelay);
|
||||
#else
|
||||
(void) RtiThreadSleep(&(pCoverage->coverageDelay));
|
||||
#endif
|
||||
#else
|
||||
(void) RtiThreadSleep(&(pCoverage->coverageDelay));
|
||||
#endif
|
||||
} /* END while */
|
||||
|
||||
if (pCoverage->exitSignal)
|
||||
{
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Received exit signal...out of link thread..\n");
|
||||
}
|
||||
pCoverage->threadStatus=LINK_THREAD_EXITING;
|
||||
|
||||
/* If we went out the the while loop for any reason other than a shutdown
|
||||
* request
|
||||
*/
|
||||
if (pCoverage->exitSignal!=EXIT_SIGNAL_SHUTDOWN)
|
||||
{
|
||||
CoverageShutDownInternal(pCoverage);
|
||||
CoverageShutDownServer(pCoverage);
|
||||
free(pCoverage);
|
||||
CoverageInfo=NULL;
|
||||
}
|
||||
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
CoverageRemoveRtpSupport();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/* datasend.pkg.h - built from: datasend.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef datasend_pkg_h
|
||||
#define datasend_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern unsigned int CODECOVERAGE_LIB_VERSION;
|
||||
|
||||
|
||||
extern CoverageDaemonInfo* CoverageInfo;
|
||||
|
||||
|
||||
|
||||
extern int CodeCoverAgentVersionGet(void);
|
||||
|
||||
|
||||
/**
|
||||
* Extended api for starting Coverage server, allows user to
|
||||
* specify more parameters
|
||||
*/
|
||||
extern int CoverageInitServerEx(int verbosity, int priority, int tcpPortNumber);
|
||||
|
||||
|
||||
/**
|
||||
* Internal call to Coverage Init server.
|
||||
*/
|
||||
extern int CoverageInitServerInternal(CoverageDaemonInfo* pCoverage, int priority, int tcpPortNumber);
|
||||
|
||||
|
||||
/**
|
||||
* CoverageInit - Initialize data structures for Coverage
|
||||
*/
|
||||
extern CoverageDaemonInfo * CoverageInit(int verbosity);
|
||||
|
||||
|
||||
/**
|
||||
* return the link status
|
||||
*/
|
||||
extern int getLinkStatus(void);
|
||||
|
||||
|
||||
/**
|
||||
* return status indicating if we have the arrays
|
||||
*/
|
||||
extern int getArrayFoundStatus(void);
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown Coverage link- Internal Shutdown routine
|
||||
* Parameters - pointer to CoverageDaemonInfo
|
||||
*/
|
||||
extern int CoverageShutDownInternal(CoverageDaemonInfo* pCoverage);
|
||||
|
||||
|
||||
/**
|
||||
* ShutDown the Coverage Server -- Clear thread data structures
|
||||
* and free CoverageDaemonInfo data
|
||||
*/
|
||||
extern void CoverageShutDownServer(CoverageDaemonInfo* pCoverage);
|
||||
|
||||
|
||||
/**
|
||||
* External Call for CoverageShutDown, uses the global CoverageInfo
|
||||
*/
|
||||
extern int CoverageShutDown(void);
|
||||
|
||||
|
||||
/**
|
||||
* Call to set verbosity of the CoverageLink thread
|
||||
*/
|
||||
extern void CoverageSetVerbosity(int verbosity);
|
||||
|
||||
|
||||
/**
|
||||
* Main function that runs as CoverageLink thread on the target
|
||||
*/
|
||||
extern int CoverageLink(CoverageDaemonInfo* pCoverage);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* datasend_pkg_h */
|
||||
@@ -0,0 +1,680 @@
|
||||
/* handlers.c - CoverageScope message handlers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01g,10oct13,wzc Fix prevent warnings.
|
||||
01f,05jul12,wzc WIND00357415 - Remove building warnings.
|
||||
01e,25jul11,flu Fixed building error for auto test (RQ:WIND00267114)
|
||||
01d,23feb11,vhe Fixed coverity warnings (CQ:WIND00256594)
|
||||
01c,10feb10,flu Change code for 64-bit porting.
|
||||
01b,05mar10,flu Modified the code for diab compilation (CQ:WIND00146073)
|
||||
01b,27jul09,jfu Clear existing coverage data via
|
||||
RESET_ALL_COVERAGE_ARRAYS/RESET_ALL_COVERAGE_ARRAYS
|
||||
commands for requirement 170416
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
CoverageScope message handlers
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
/* fix win32 snprintf */
|
||||
#ifdef RTI_WIN32
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
# include <vxWorks.h>
|
||||
# include <vsbConfig.h>
|
||||
# include <private/kernelBaseLibP.h>
|
||||
# include <private/taskLibP.h>
|
||||
# include <private/taskMemLibP.h>
|
||||
|
||||
# include <rtilib/vxVersions.h>
|
||||
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define KERNEL_ID kernelIdGet()
|
||||
# else
|
||||
# define KERNEL_ID kernelId
|
||||
# endif
|
||||
# else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define KERNEL_ID kernelIdGet()
|
||||
# else
|
||||
# define KERNEL_ID kernelId
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <rtilib/makeheader.h>
|
||||
|
||||
#pragma begin_Peer
|
||||
#include "coveragedata.pkg.h"
|
||||
#include "coveragenet.pkg.h"
|
||||
#include "handlers.pkg.h"
|
||||
#include "symfind.pkg.h"
|
||||
#include "utils.pkg.h"
|
||||
#pragma end_Peer
|
||||
|
||||
extern char* mystrsplit(char* s, char delim, char** ppLast);
|
||||
|
||||
/*------------------------static function prototypes------------------*/
|
||||
Private int coverageSendCoverageArray(CoverageDaemonInfo* pCoverage,\
|
||||
int currentArrayNumber);
|
||||
|
||||
Private
|
||||
int CoverageSendWriteBuff(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
int sendStatus=0;
|
||||
if((sendStatus = CoverageDataSend(pCoverage, pCoverage->writeBuff,
|
||||
strlen(pCoverage->writeBuff))) < 0)
|
||||
{
|
||||
CoverageV2Warning(pCoverage->debugLevel)
|
||||
("Link: Error #%d: Error sending data! Exiting...\n", sendStatus);
|
||||
}
|
||||
return sendStatus;
|
||||
}
|
||||
|
||||
/* -----------------Handler function for XML interpreter---------------*/
|
||||
|
||||
/* CoverageAddArraysAddrs - Handle the XML command that gives a set of Array Names
|
||||
* and their addresses on the target.
|
||||
* Use library routines in symfind.c to parse Array names(string separated by :)
|
||||
*/
|
||||
Peer
|
||||
void CoverageAddArraysAddrs(const void *xmlHandle)
|
||||
{
|
||||
// TD: we alter the string, but do we really need to copy the whole thing?
|
||||
char* intArrayNames= STRDUP(parseParamString("commandData",xmlHandle));
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * str;
|
||||
|
||||
if (0 == intArrayNames) {
|
||||
printf("Out of memory while adding arrays and addresses\n");
|
||||
return;
|
||||
}
|
||||
str = parseParamString("pCoverage",xmlHandle);
|
||||
if (str == NULL) {
|
||||
printf("Not Found pCoverage\n");
|
||||
free(intArrayNames);
|
||||
return;
|
||||
}
|
||||
|
||||
pCoverage = (CoverageDaemonInfo*)
|
||||
(strtoul(str,(char **) NULL, 10));
|
||||
|
||||
/*Get pointer to all coverage arrays*/
|
||||
findAllArraysByName(intArrayNames,pCoverage);
|
||||
free(intArrayNames);
|
||||
pCoverage->linkStatus|=LINK_STATUS_HAVEARRAY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear up all book keeping entries for target arrays.
|
||||
*/
|
||||
|
||||
Peer
|
||||
void CoverageClearAllArrayInfo(const void* xmlHandle)
|
||||
{
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * cov = parseParamString("pCoverage",xmlHandle);
|
||||
|
||||
if (cov == NULL)
|
||||
return;
|
||||
|
||||
pCoverage = (CoverageDaemonInfo*)strtoul(cov,(char **) NULL, 10);
|
||||
|
||||
if (pCoverage == NULL)
|
||||
return;
|
||||
|
||||
if (pCoverage->numArrays>0)
|
||||
{
|
||||
if (pCoverage->debugLevel>1)
|
||||
{
|
||||
printf("Freeing all array info to reinitialise");
|
||||
}
|
||||
CoverageClearArrayInfo(pCoverage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ClearArrayInfo -
|
||||
* If host side disconnects we clear all information we have about arrays
|
||||
* we are collecting.(eg. array names) When the host reconnects it sends in
|
||||
* the list of Arrays it wants to monitor.
|
||||
*/
|
||||
Peer
|
||||
int CoverageClearArrayInfo(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
int i;
|
||||
if (pCoverage->pCoverageArray!=NULL)
|
||||
{
|
||||
free(pCoverage->pCoverageArray);
|
||||
}
|
||||
if (pCoverage->coverageArrayNames!=NULL)
|
||||
{
|
||||
for (i=0;i<pCoverage->numArrays;i++)
|
||||
{
|
||||
free(pCoverage->coverageArrayNames[i]);
|
||||
}
|
||||
free(pCoverage->coverageArrayNames);
|
||||
}
|
||||
pCoverage->pCoverageArray=NULL;
|
||||
pCoverage->coverageArrayNames=NULL;
|
||||
pCoverage->numArrays=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ConnectConfirm
|
||||
* When we send an XML command telling the host that we are connected and give
|
||||
* it the endianness information, the host sends a connection confirmation.
|
||||
* This function handles the acknowledgement of
|
||||
* this command.
|
||||
*/
|
||||
Peer
|
||||
void CoverageConnectConfirm(const void* xmlHandle)
|
||||
{
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * cov = parseParamString("pCoverage",xmlHandle);
|
||||
|
||||
if (cov == NULL)
|
||||
return;
|
||||
|
||||
pCoverage = (CoverageDaemonInfo*)strtoul(cov, (char **) NULL, 10);
|
||||
|
||||
if (pCoverage == NULL)
|
||||
return;
|
||||
|
||||
pCoverage->connectionUp=RTI_TRUE;
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Connection Confirmed from host side\n");
|
||||
}
|
||||
|
||||
|
||||
/* SendCoverageArrays
|
||||
* Send back data to the host side in return of a request
|
||||
* If the arrays are too big we can't send in one shot
|
||||
*/
|
||||
Peer
|
||||
void CoverageSendAllCoverageArrays(const void* xmlHandle)
|
||||
{
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * cov = parseParamString("pCoverage",xmlHandle);
|
||||
|
||||
if (cov == NULL)
|
||||
return;
|
||||
|
||||
pCoverage = (CoverageDaemonInfo*)strtoul(cov,(char **) NULL, 10);
|
||||
|
||||
if (pCoverage == NULL)
|
||||
return;
|
||||
|
||||
CoverageSendAllCoverageArraysInt(pCoverage);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void CoverageSendAllCoverageArraysInt(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
unsigned int currentArrayNumber = 0;
|
||||
|
||||
/*We have the array names, let's send data*/
|
||||
/*send the arrays one by one in packets of XML Commands*/
|
||||
|
||||
if (GET_LINK_STATUS(pCoverage->linkStatus)==LINK_STATUS_COLLECTING) {
|
||||
/* Already collecting... */
|
||||
return;
|
||||
}
|
||||
|
||||
pCoverage->linkStatus = (((pCoverage->linkStatus)&(INT8)LINK_MASK_HAVEARRAY)
|
||||
|(INT8)LINK_STATUS_COLLECTING);
|
||||
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("In Send all Coverage handler sending: %d arrays\n",
|
||||
pCoverage->numArrays);
|
||||
|
||||
while (currentArrayNumber<pCoverage->numArrays) {
|
||||
/*Quit if exit has been signalled*/
|
||||
if (pCoverage->exitSignal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!HAVE_ARRAY(pCoverage->linkStatus))
|
||||
{
|
||||
/*Should we ask the host for array names*/
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("We don't have an array :((\n");
|
||||
} else {
|
||||
if (coverageSendCoverageArray(pCoverage,currentArrayNumber) < 0)
|
||||
{
|
||||
pCoverage->exitSignal = EXIT_SIGNAL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentArrayNumber++;
|
||||
}
|
||||
pCoverage->linkStatus = (((pCoverage->linkStatus)&(INT8)LINK_MASK_HAVEARRAY)
|
||||
|(INT8)LINK_STATUS_CONNECTED);
|
||||
|
||||
if (pCoverage->debugLevel>0)
|
||||
printf("Out of Send all Coverage handler\n");
|
||||
}
|
||||
|
||||
Private
|
||||
int coverageSendCoverageArray(CoverageDaemonInfo* pCoverage,
|
||||
int currentArrayNumber)
|
||||
{
|
||||
int startIndex=0;
|
||||
int endIndex=0;
|
||||
int arrayLength=0;
|
||||
int encodedLength=0;
|
||||
int status;
|
||||
|
||||
if (pCoverage->pCoverageArray[currentArrayNumber]==NULL)
|
||||
{
|
||||
if (pCoverage->debugLevel>2)
|
||||
printf("Array %s could not be located\n",\
|
||||
pCoverage->coverageArrayNames[currentArrayNumber]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* use taskCtxSwitch to read the array from a different pd */
|
||||
/* TD: use the _func_taskMemCtxSwitch() function pointer */
|
||||
/*printf("Switching to %x (%x)\n", pCoverage->coverageArrayPdId[currentArrayNumber], kernelId);*/
|
||||
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
if(pCoverage->coverageArrayPdId[currentArrayNumber] != KERNEL_ID) {
|
||||
if (0 == _func_taskMemCtxSwitch((RTP_ID)pCoverage->
|
||||
coverageArrayPdId[currentArrayNumber], 0))
|
||||
{
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("Could not read array %s from pd 0x%lx\n",
|
||||
pCoverage->coverageArrayNames[currentArrayNumber],
|
||||
(long)pCoverage->coverageArrayPdId[currentArrayNumber]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
arrayLength=pCoverage->pCoverageArray[currentArrayNumber][0];
|
||||
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
if(pCoverage->coverageArrayPdId[currentArrayNumber] != KERNEL_ID) {
|
||||
_func_taskMemCtxSwitch (KERNEL_ID, 0);
|
||||
}
|
||||
#endif
|
||||
arrayLength*=(int)sizeof(int); /*Convert into number of bytes*/
|
||||
|
||||
while (arrayLength>0)
|
||||
{
|
||||
startIndex=endIndex;
|
||||
endIndex=startIndex+COVERAGE_MIN(arrayLength,XML_DATASIZE);
|
||||
memset(pCoverage->encodedData,0,XML_ENCODEDSIZE);
|
||||
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
if(pCoverage->coverageArrayPdId[currentArrayNumber] != KERNEL_ID) {
|
||||
_func_taskMemCtxSwitch((RTP_ID)pCoverage->coverageArrayPdId[currentArrayNumber], 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
base64Encode(((unsigned char*)(pCoverage->pCoverageArray\
|
||||
[currentArrayNumber]))+startIndex,
|
||||
(unsigned char*)pCoverage->encodedData,
|
||||
endIndex-startIndex,&encodedLength);
|
||||
|
||||
#ifdef _WRS_CONFIG_RTP
|
||||
if(pCoverage->coverageArrayPdId[currentArrayNumber] != KERNEL_ID) {
|
||||
_func_taskMemCtxSwitch (KERNEL_ID, 0);
|
||||
}
|
||||
#endif
|
||||
arrayLength-=XML_DATASIZE;
|
||||
snprintf(pCoverage->writeBuff, LINK_WRITESIZE,
|
||||
"<Command name=\"ARRAY\" numparam=\"1\">\n"
|
||||
"<Param startIndex=\"%d\"></Param>\n"
|
||||
"<Param count=\"%d\"></Param>\n"
|
||||
"<Param arrayName=\"%s\">\"%s\"</Param>\n"
|
||||
"</Command>\n",(int)(startIndex/sizeof(int)),
|
||||
(int)(endIndex/sizeof(int)),
|
||||
(char*)(pCoverage->coverageArrayNames[currentArrayNumber]),
|
||||
pCoverage->encodedData);
|
||||
if (pCoverage->debugLevel>3)
|
||||
printf("Sending over the network:%s\n",pCoverage->writeBuff);
|
||||
|
||||
if ((status = CoverageSendWriteBuff(pCoverage)) < 0)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler to shutdown the link
|
||||
*/
|
||||
Peer
|
||||
void CoverageLinkShutDown(const void* xmlHandle)
|
||||
{
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * cov = parseParamString("pCoverage",xmlHandle);
|
||||
if (cov == NULL)
|
||||
return;
|
||||
|
||||
pCoverage = (CoverageDaemonInfo*)
|
||||
(strtoul(cov,(char **) NULL, 10));
|
||||
|
||||
if (pCoverage == NULL)
|
||||
return;
|
||||
|
||||
pCoverage->exitSignal=EXIT_SIGNAL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CoverageLocateArrays - Handle the XML command that gives a set of Array Names
|
||||
* Use library routines in symfind.c to parse Array names(string separated by :)
|
||||
*/
|
||||
Peer
|
||||
void CoverageAddArraySymbols(const void* xmlHandle)
|
||||
{
|
||||
// TD: we alter the string, but do we really need to copy the whole thing?
|
||||
char* intArrayNames = STRDUP(parseParamString("commandData",xmlHandle));
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * str;
|
||||
if (0 == intArrayNames) {
|
||||
printf("Out of memory while adding arrays\n");
|
||||
return;
|
||||
}
|
||||
str = parseParamString("pCoverage",xmlHandle);
|
||||
if (str == NULL) {
|
||||
printf("Not Found pCoverage\n");
|
||||
free(intArrayNames);
|
||||
return;
|
||||
}
|
||||
pCoverage = (CoverageDaemonInfo*)
|
||||
(strtoul(str,(char **) NULL, 10));
|
||||
|
||||
/*Get pointer to all coverage arrays*/
|
||||
findAllArraysByName(intArrayNames,pCoverage);
|
||||
free(intArrayNames);
|
||||
pCoverage->linkStatus|=LINK_STATUS_HAVEARRAY;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/*
|
||||
*Clear array datas to zero based on the parameter array poniter
|
||||
*parameter flag distinguish the array format that starts with
|
||||
*WRS_xxx or RTI_Cover_xxx
|
||||
*/
|
||||
void setArray(CVGARRAYTYPE *array,char flag)
|
||||
{
|
||||
int nBytes;
|
||||
|
||||
/* sanity check */
|
||||
if (NULL == array){
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
/* array format that starts with WRS_xxx */
|
||||
nBytes = (array[1]-2) * (int)sizeof(int);
|
||||
bzero((char*)(array+2), nBytes);
|
||||
}
|
||||
else {
|
||||
/*array format that starts with RTI_Cover_xxx*/
|
||||
nBytes = (array[0]-2) * (int)sizeof(int);
|
||||
bzero((char*)(array+1), nBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/*
|
||||
*Clear array datas based on index
|
||||
*parameter NewArrayFlag shows whether a new array created
|
||||
*0-no new array created 1-new array created
|
||||
*/
|
||||
void ClearArrayDatas(CoverageDaemonInfo* pCoverage, int index, char* NewArrayFlag)
|
||||
{
|
||||
int arrayLength = 0, arrayTotal = 0, arrayMem = 0;
|
||||
char flag;
|
||||
|
||||
arrayLength = pCoverage->pCoverageArray[index][0];
|
||||
|
||||
if (0 == strncasecmp(pCoverage->coverageArrayNames[index], "WRS_", 4)) {
|
||||
/* new array format */
|
||||
flag = 1;
|
||||
|
||||
arrayTotal = pCoverage->pCoverageArray[index][1];
|
||||
|
||||
/* simple sanity check */
|
||||
if ((arrayLength <= 2) || (arrayLength <= arrayTotal) || (arrayTotal < 2)) {
|
||||
printf("Array %s has inconsistent size information, skipping\n",\
|
||||
pCoverage->coverageArrayNames[index]);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* old array format */
|
||||
flag = 0;
|
||||
/* simple sanity check */
|
||||
if (arrayLength <= 2) {
|
||||
printf("Array %s has inconsistent size information, skipping\n",\
|
||||
pCoverage->coverageArrayNames[index]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag == 1)
|
||||
arrayMem = pCoverage->pCoverageArray[index][2];
|
||||
else if (flag == 0)
|
||||
arrayMem = pCoverage->pCoverageArray[index][1];
|
||||
|
||||
if (arrayMem != 0){
|
||||
/*a new array created*/
|
||||
*NewArrayFlag = 1;
|
||||
}
|
||||
else {
|
||||
/*no new array created*/
|
||||
*NewArrayFlag = 0;
|
||||
}
|
||||
|
||||
setArray(pCoverage->pCoverageArray[index], flag);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/* iterate over all the coverage arrays to clear all the array datas */
|
||||
void FindAllArrays(CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
int index;
|
||||
char flag = 0;
|
||||
|
||||
for (index = 0; index < pCoverage->numArrays; index++) {
|
||||
|
||||
if (pCoverage->coverageArrayPdId[index] != KERNEL_ID) {
|
||||
if (0 == taskMemCtxSwitch((RTP_ID)pCoverage->coverageArrayPdId[index], 0)) {
|
||||
if (pCoverage->debugLevel > 1)
|
||||
printf("Could not read array %s from pd 0x%lx\n",pCoverage->coverageArrayNames[index],\
|
||||
(long)pCoverage->coverageArrayPdId[index]);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (pCoverage->pCoverageArray[index] == NULL) {
|
||||
if (pCoverage->debugLevel > 1)
|
||||
printf("Array %s could not be located\n", pCoverage->coverageArrayNames[index]);
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
/* check coverage array format:
|
||||
* - array names starting with "WRS_" use a new format
|
||||
* - others use the 'old' format.
|
||||
*/
|
||||
|
||||
ClearArrayDatas(pCoverage, index, &flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* iterate over all the coverage arrays to find the right arrays */
|
||||
void FindCoverArrays(CoverageDaemonInfo* pCoverage, char *arrayName)
|
||||
{
|
||||
int index;
|
||||
char flag = 0;
|
||||
|
||||
if (arrayName == NULL)
|
||||
return;
|
||||
|
||||
for (index=0; index < pCoverage->numArrays; index++) {
|
||||
|
||||
if(pCoverage->coverageArrayPdId[index] != KERNEL_ID) {
|
||||
if (0 == taskMemCtxSwitch((RTP_ID)pCoverage->coverageArrayPdId[index], 0)) {
|
||||
if (pCoverage->debugLevel > 1)
|
||||
printf("Could not read array %s from pd 0x%lx\n",pCoverage->coverageArrayNames[index],\
|
||||
(long)pCoverage->coverageArrayPdId[index]);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (pCoverage->pCoverageArray[index] == NULL) {
|
||||
if (pCoverage->debugLevel > 1)
|
||||
printf("Array %s could not be located\n", pCoverage->coverageArrayNames[index]);
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (strcmp (arrayName,pCoverage->coverageArrayNames[index]) == 0) {
|
||||
|
||||
ClearArrayDatas(pCoverage, index, &flag);
|
||||
|
||||
if (flag)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/*
|
||||
* Clear out array data to reset everything to zero
|
||||
*/
|
||||
void CoverageResetAllArrays(const void* xmlHandle)
|
||||
{
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * cov = parseParamString("pCoverage",xmlHandle);
|
||||
if (cov == NULL)
|
||||
return;
|
||||
|
||||
pCoverage = (CoverageDaemonInfo*)strtoul(cov,(char **) NULL, 10);
|
||||
|
||||
if (pCoverage == NULL)
|
||||
return;
|
||||
|
||||
/* if there is no array registered yet, we're done */\
|
||||
if (pCoverage->numArrays <= 0)
|
||||
return;
|
||||
|
||||
if (pCoverage->debugLevel > 1)
|
||||
printf("Reset all coverage arrays\n");
|
||||
|
||||
FindAllArrays(pCoverage);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Peer
|
||||
/*
|
||||
* Clear out some fixed session array datas based on the array name list
|
||||
* that given in command parameters
|
||||
*/
|
||||
void CoverageResetArrays(const void * xmlHandle)
|
||||
{
|
||||
int count=0;
|
||||
int numArrays;
|
||||
char* arrayName;
|
||||
char* ppLast=NULL;
|
||||
CoverageDaemonInfo* pCoverage;
|
||||
char * coverage;
|
||||
char* ArrayNamesList;
|
||||
char* aNamList;
|
||||
|
||||
aNamList = parseParamString("array_name_list",xmlHandle);
|
||||
if (aNamList == NULL)
|
||||
return;
|
||||
|
||||
ArrayNamesList= strdup(aNamList);
|
||||
if (ArrayNamesList == NULL)
|
||||
return;
|
||||
|
||||
coverage = parseParamString("pCoverage", xmlHandle);
|
||||
if (coverage == NULL)
|
||||
{
|
||||
free (ArrayNamesList);
|
||||
return;
|
||||
}
|
||||
pCoverage = (CoverageDaemonInfo*) \
|
||||
(strtoul(coverage, (char **) NULL, 10));
|
||||
|
||||
numArrays = findNumArrays(ArrayNamesList);
|
||||
count = numArrays;
|
||||
|
||||
/* if there is no array registered yet, we're done */
|
||||
if (pCoverage->numArrays <= 0)
|
||||
{
|
||||
free (ArrayNamesList);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pCoverage->debugLevel > 1)
|
||||
printf("Reset coverage arrays\n");
|
||||
|
||||
do {
|
||||
if (count == numArrays)
|
||||
arrayName = mystrsplit(ArrayNamesList, ':', &ppLast);
|
||||
else
|
||||
arrayName = mystrsplit(NULL, ':', &ppLast);
|
||||
|
||||
FindCoverArrays(pCoverage, arrayName);
|
||||
|
||||
count --;
|
||||
} while (count > 0);
|
||||
|
||||
/* free allocated string */
|
||||
free (ArrayNamesList);
|
||||
}
|
||||
|
||||
// unfix win32 snprintf
|
||||
#ifdef RTI_WIN32
|
||||
#undef snprintf
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/* handlers.pkg.h - built from: handlers.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef handlers_pkg_h
|
||||
#define handlers_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include "coveragedata.pkg.h"
|
||||
#include "coveragenet.pkg.h"
|
||||
#include "handlers.pkg.h"
|
||||
#include "symfind.pkg.h"
|
||||
#include "utils.pkg.h"
|
||||
|
||||
|
||||
extern void CoverageAddArraysAddrs(const void *xmlHandle);
|
||||
|
||||
|
||||
extern void CoverageClearAllArrayInfo(const void* xmlHandle);
|
||||
|
||||
|
||||
extern int CoverageClearArrayInfo(CoverageDaemonInfo* pCoverage);
|
||||
|
||||
|
||||
extern void CoverageConnectConfirm(const void* xmlHandle);
|
||||
|
||||
|
||||
extern void CoverageSendAllCoverageArrays(const void* xmlHandle);
|
||||
|
||||
|
||||
extern void CoverageSendAllCoverageArraysInt(CoverageDaemonInfo* pCoverage);
|
||||
|
||||
|
||||
extern void CoverageLinkShutDown(const void* xmlHandle);
|
||||
|
||||
|
||||
extern void CoverageAddArraySymbols(const void* xmlHandle);
|
||||
|
||||
|
||||
/*
|
||||
* Clear out array data to reset everything to zero
|
||||
*/
|
||||
extern void CoverageResetAllArrays(const void* xmlHandle);
|
||||
|
||||
|
||||
/*
|
||||
* Clear out some fixed session array datas based on the array name list
|
||||
* that given in command parameters
|
||||
*/
|
||||
extern void CoverageResetArrays(const void * xmlHandle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* handlers_pkg_h */
|
||||
@@ -0,0 +1,212 @@
|
||||
/* rtp_support.c - Support RTP function */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010, 2012, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,09oct13,wzc Fix prevent warnings.
|
||||
01c,05jul12,wzc WIND00357415 - Remove building warnings.
|
||||
01b,16dec10,zlo Use new typed error value(WIND00246074).
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Support RTP function
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <rtilib/vxVersions.h>
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
|
||||
#include <private/rtpLibP.h>
|
||||
#include <vxWorks.h>
|
||||
#include <logLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <limits.h>
|
||||
#include <msgQLib.h>
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
|
||||
#include "handlers.pkg.h"
|
||||
#include "datasend.pkg.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
/* */
|
||||
#define NUM_QUEUED_RTPS (10)
|
||||
|
||||
typedef struct {
|
||||
RTP_ID rtp_id;
|
||||
SEM_ID exit_lock;
|
||||
} ExitMessage;
|
||||
|
||||
|
||||
Private MSG_Q_ID CoveragePendingRTPs = MSG_Q_ID_NULL;
|
||||
|
||||
#if VXWORKS_VERSION_6_0_OR_BETTER
|
||||
Private void rtpDeleteHook(const RTP_ID rtpId, const int exitCode);
|
||||
#endif
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void CoverageInitRtpSupport(void)
|
||||
{
|
||||
CoveragePendingRTPs = msgQCreate(NUM_QUEUED_RTPS,
|
||||
sizeof(ExitMessage), MSG_Q_FIFO);
|
||||
if (MSG_Q_ID_NULL == CoveragePendingRTPs) {
|
||||
logMsg("Failed to create RTP exit message queue, Coverage data from exiting RTPs will not be gathered\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_func_rtpDeleteHookAdd != 0) {
|
||||
if (ERROR == (*rtpDeleteHookAdd)(rtpDeleteHook, FALSE)) {
|
||||
logMsg("Error adding rtp delete hook, you may loose data\n");
|
||||
}
|
||||
} else {
|
||||
logMsg("No RTP hook support found, Coverage data from exiting RTPs will not be gathered\n");
|
||||
msgQDelete(CoveragePendingRTPs);
|
||||
CoveragePendingRTPs = MSG_Q_ID_NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void CoverageRemoveRtpSupport(void)
|
||||
{
|
||||
/* remove our rtp data collection callbacks */
|
||||
if (_func_rtpDeleteHookDelete != 0) {
|
||||
if (ERROR == (*_func_rtpDeleteHookDelete) (rtpDeleteHook)) {
|
||||
/* fail silently */
|
||||
/* logMsg(""); */
|
||||
}
|
||||
}
|
||||
|
||||
msgQDelete(CoveragePendingRTPs);
|
||||
CoveragePendingRTPs = MSG_Q_ID_NULL;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void CoverageWaitForRTPs(const unsigned int ticks)
|
||||
{
|
||||
ExitMessage msg;
|
||||
unsigned long startTick, endTick, currentTick;
|
||||
|
||||
if (MSG_Q_ID_NULL == CoveragePendingRTPs) {
|
||||
taskDelay(ticks);
|
||||
return;
|
||||
}
|
||||
|
||||
startTick = tickGet();
|
||||
endTick = startTick + ticks;
|
||||
|
||||
/* to ensure absolute data integrity, we empty the queue,
|
||||
send up the arrays, THEN release the semaphores. This avoids
|
||||
an RTP exiting after we send up the data, but before we empty
|
||||
the queue... */
|
||||
|
||||
if (ERROR != msgQReceive(CoveragePendingRTPs, (char *) &msg,
|
||||
sizeof(msg), ticks))
|
||||
{
|
||||
SEM_ID locks[NUM_QUEUED_RTPS];
|
||||
const ssize_t numMsgs = msgQNumMsgs(CoveragePendingRTPs);
|
||||
int i;
|
||||
ExitMessage tmpMsg;
|
||||
|
||||
/* empty the queue of exiting RTPs */
|
||||
if (numMsgs > 0) {
|
||||
for (i = 0; i < numMsgs; ++i) {
|
||||
if (ERROR != msgQReceive(CoveragePendingRTPs, (char *) &tmpMsg,
|
||||
sizeof(tmpMsg), NO_WAIT))
|
||||
{
|
||||
/* should we throw an error here? */
|
||||
locks[i] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
locks[i] = tmpMsg.exit_lock;
|
||||
}
|
||||
|
||||
/* send up coverage data */
|
||||
CoverageSendAllCoverageArraysInt(CoverageInfo);
|
||||
|
||||
/* release locked RTPs */
|
||||
for (i = 0; i < numMsgs; ++i) {
|
||||
if (0 == locks[i]) {
|
||||
break;
|
||||
}
|
||||
(void)semGive(locks[i]);
|
||||
}
|
||||
}
|
||||
(void)semGive(msg.exit_lock);
|
||||
}
|
||||
|
||||
|
||||
/* delay for the rest of the requested period, taking into account
|
||||
timer wraparound */
|
||||
currentTick = tickGet();
|
||||
|
||||
if (startTick < endTick) {
|
||||
/* no wraparound */
|
||||
if ( (currentTick > startTick) && (endTick > currentTick) ) {
|
||||
taskDelay((_Vx_ticks_t)(endTick - currentTick));
|
||||
}
|
||||
} else {
|
||||
if (currentTick > startTick) {
|
||||
taskDelay((_Vx_ticks_t)(ULONG_MAX - currentTick + endTick));
|
||||
} else if (currentTick < endTick) {
|
||||
taskDelay((_Vx_ticks_t)(endTick - currentTick));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void rtpDeleteHook(const RTP_ID rtpId, const int exitCode)
|
||||
{
|
||||
ExitMessage msg;
|
||||
|
||||
// logMsg("Delete hook called\n");
|
||||
msg.rtp_id = 0;
|
||||
msg.exit_lock = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
|
||||
|
||||
if (SEM_ID_NULL == msg.exit_lock) {
|
||||
logMsg("Failed to allocate semaphore for RTP %p, Coverage data will not be collected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ERROR == msgQSend(CoveragePendingRTPs, (char *) &msg, sizeof(msg),
|
||||
WAIT_FOREVER, MSG_PRI_NORMAL))
|
||||
{
|
||||
(void)semDelete(msg.exit_lock);
|
||||
logMsg("Failed send exit notification for RTP %p, Coverage data will not be collected.\n");
|
||||
}
|
||||
|
||||
(void)semTake(msg.exit_lock, WAIT_FOREVER);
|
||||
(void)semDelete(msg.exit_lock);
|
||||
// logMsg("Exiting\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/* rtp_support.pkg.h - built from: rtp_support.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rtp_support_pkg_h
|
||||
#define rtp_support_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern void CoverageInitRtpSupport(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern void CoverageRemoveRtpSupport(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern void CoverageWaitForRTPs(const unsigned int ticks);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rtp_support_pkg_h */
|
||||
@@ -0,0 +1,474 @@
|
||||
/* shmlib.c - Shared memory lib */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01b,29jun12,wzc WIND00350881 - check malloc return value.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
/* $Id: shmlib.c,v 1.3 2007/10/01 19:51:13 panderse Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Shared memory lib
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include "coveragedata.pkg.h"
|
||||
#include "datasend.pkg.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#pragma begin_Peer
|
||||
#ifndef _SHMLIB_H /* needed because there's currently a circular dependency in
|
||||
our package header files; shmlib.c depends on
|
||||
coveragedata.pkg.h, which depends on shmlib.pkg.h */
|
||||
#define _SHMLIB_H
|
||||
#define MAX_FILENAME_LEN 256
|
||||
#define MINIMUM_ARRAY_SIZE 256
|
||||
#define MAX_ARRAY_NAME 256
|
||||
#define SHARED_VERSION 0x00010000
|
||||
#define COVERAGE_MAP_FLAGS (MAP_SHARED)
|
||||
|
||||
#define RtiError(fmt,...) printf("ERROR: %s [%s@%d]: " \
|
||||
fmt,__func__,__FILE__,__LINE__,##__VA_ARGS__)
|
||||
|
||||
#if DEBUG>0
|
||||
#define RtiInfo(fmt,...) printf("INFO: %s [%s@%d]: " \
|
||||
fmt,__func__,__FILE__,__LINE__,##__VA_ARGS__)
|
||||
#else
|
||||
#define RtiInfo(fmt,...)
|
||||
#endif
|
||||
|
||||
#if DEBUG>1
|
||||
#define RtiDebug(fmt,...) printf("DEBUG: %s [%s@%d]: " \
|
||||
fmt,__func__,__FILE__,__LINE__,##__VA_ARGS__)
|
||||
#else
|
||||
#define RtiDebug(fmt,...)
|
||||
#endif
|
||||
|
||||
typedef struct shared_t {
|
||||
unsigned long version;
|
||||
unsigned long size;
|
||||
unsigned long free_len;
|
||||
unsigned long free_page;
|
||||
unsigned long free_off;
|
||||
unsigned long n_arrays;
|
||||
unsigned long last_page;
|
||||
unsigned long last_off;
|
||||
} shared_t;
|
||||
|
||||
typedef struct sharray_t {
|
||||
unsigned int length;
|
||||
unsigned long prev_page;
|
||||
unsigned long prev_off;
|
||||
unsigned long pid;
|
||||
char proc[MAX_ARRAY_NAME];
|
||||
char name[MAX_ARRAY_NAME];
|
||||
int data; /* beginning of data array */
|
||||
} sharray_t;
|
||||
|
||||
|
||||
/**
|
||||
* The shmregion_t structure is a handle for a single shared memory region;
|
||||
* there should be one of these for each file we map.
|
||||
*/
|
||||
typedef struct shmregion_t {
|
||||
shared_t *meta; /* pointer to the metadata as mapped into the current process */
|
||||
shared_t *data;
|
||||
sharray_t *arrayhead;
|
||||
char *datafile;
|
||||
char *lockfile;
|
||||
int n_arrays;
|
||||
int n_arrays_new;
|
||||
int datafd;
|
||||
int datasize;
|
||||
int initialsize;
|
||||
int deltasize;
|
||||
int pagesize;
|
||||
int valid;
|
||||
} shmregion_t;
|
||||
#endif
|
||||
#pragma end_Peer
|
||||
|
||||
|
||||
Peer
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void dump_shared_t(const shared_t * const data)
|
||||
{
|
||||
printf("shared_t structure @ %p:\n", data);
|
||||
printf("\tversion = 0x%lx (%ld)\n"
|
||||
"\tsize = 0x%lx (%ld)\n"
|
||||
"\tfree_len = 0x%lx (%ld)\n"
|
||||
"\tfree_page = 0x%lx (%ld)\n"
|
||||
"\tfree_off = %ld\n"
|
||||
"\tn_arrays = %ld\n"
|
||||
"\tlast_page = %ld\n"
|
||||
"\tlast_off = %ld\n",
|
||||
data->version, data->version, data->size, data->size,
|
||||
data->free_len, data->free_len, data->free_page, data->free_page,
|
||||
data->free_off, data->n_arrays, data->last_page, data->last_off);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void CoverageShmLock(const shmregion_t * const shm)
|
||||
{
|
||||
int fd;
|
||||
while ((fd = open(shm->lockfile,O_CREAT | O_EXCL | O_WRONLY,0)) < 0) {
|
||||
if (errno != EEXIST) {
|
||||
RtiError("Failed to create lock-file %s\n",shm->lockfile);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void CoverageShmUnlock(const shmregion_t * const shm)
|
||||
{
|
||||
unlink(shm->lockfile);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
int CoverageCreateDataFile(shmregion_t *shm)
|
||||
{
|
||||
RtiDebug("enter\n");
|
||||
shm->datafd = open(shm->datafile,
|
||||
O_CREAT | O_RDWR,
|
||||
S_IRUSR | S_IWUSR
|
||||
| S_IRGRP|S_IWGRP
|
||||
| S_IROTH|S_IWOTH);
|
||||
|
||||
if (shm->datafd < 0) {
|
||||
return -1;
|
||||
}
|
||||
ftruncate(shm->datafd,shm->initialsize);
|
||||
shm->datasize = shm->initialsize;
|
||||
RtiDebug("exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void CoverageShmInitMeta(shmregion_t *shm)
|
||||
{
|
||||
shm->meta->version = SHARED_VERSION;
|
||||
shm->meta->size = shm->datasize;
|
||||
shm->meta->free_len = shm->meta->size - shm->pagesize;
|
||||
shm->meta->free_page = shm->pagesize;
|
||||
shm->meta->free_off = 0;
|
||||
shm->meta->n_arrays = 0;
|
||||
shm->meta->last_page = 0;
|
||||
shm->meta->last_off = 0;
|
||||
}
|
||||
|
||||
|
||||
Private inline
|
||||
/**
|
||||
*
|
||||
*/
|
||||
sharray_t * next_array(const shmregion_t * const region,
|
||||
const sharray_t * const current_array)
|
||||
{
|
||||
return (sharray_t *) ((void *)region->data
|
||||
+ current_array->prev_page
|
||||
+ current_array->prev_off);
|
||||
}
|
||||
|
||||
|
||||
Private inline
|
||||
/**
|
||||
*
|
||||
*/
|
||||
sharray_t * last_array(const shmregion_t * const region)
|
||||
{
|
||||
return (sharray_t *) ((void *)region->data
|
||||
+ region->meta->last_page
|
||||
+ region->meta->last_off);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void CoverageShmArrayAdd(shmregion_t *shm, sharray_t *newhead)
|
||||
{
|
||||
const sharray_t *array = newhead;
|
||||
|
||||
while (array != shm->arrayhead) {
|
||||
RtiInfo("proc [%s/%lu]. array [%s]: length=%u\n",
|
||||
array->proc,array->pid,array->name,array->length);
|
||||
array = next_array(shm, array);
|
||||
shm->n_arrays++;
|
||||
}
|
||||
|
||||
shm->arrayhead = newhead;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
int CoverageShmInitInternal(shmregion_t *shm, const char * const filename,
|
||||
int fc, int datasize, int increment)
|
||||
{
|
||||
int newfile = 0;
|
||||
|
||||
shm->datafile = strdup(filename);
|
||||
shm->lockfile = malloc(strlen(filename)+5);
|
||||
if (shm->lockfile == NULL) {
|
||||
RtiError("failed to malloc memory, %d\n",errno);
|
||||
return -1;
|
||||
}
|
||||
strcpy(shm->lockfile,shm->datafile);
|
||||
strcat(shm->lockfile,".lck");
|
||||
shm->pagesize = getpagesize();
|
||||
shm->initialsize = datasize;
|
||||
shm->deltasize = increment;
|
||||
shm->n_arrays = 0;
|
||||
shm->valid = 1;
|
||||
CoverageShmLock(shm);
|
||||
|
||||
shm->datafd = open(filename,O_RDWR);
|
||||
|
||||
if (shm->datafd < 0) {
|
||||
if (errno == ENOENT) {
|
||||
if (fc) {
|
||||
if (!CoverageCreateDataFile(shm)) {
|
||||
newfile = 1;
|
||||
} else {
|
||||
RtiError("failed to open/create shared file, %d\n",errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shm->datafd < 0) {
|
||||
RtiError("failed to open/create shared file, %d\n",errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//TD: it doesn't seem necessary to have separate mappings for shm-meta and shm->data; they both point to the same shared memory. I believe meta is mapped first to gather the size for the data mapping, but this can be done without having to maintain two mappings (and pointers).
|
||||
|
||||
shm->meta = (shared_t*)mmap(0,sizeof(struct shared_t),
|
||||
PROT_READ | PROT_WRITE,
|
||||
COVERAGE_MAP_FLAGS,
|
||||
shm->datafd,0);
|
||||
|
||||
if ((long)shm->meta == -1) {
|
||||
RtiError("failed to map meta data, (%d)\n",errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (newfile) {
|
||||
CoverageShmInitMeta(shm);
|
||||
} else {
|
||||
shm->datasize = shm->meta->size;
|
||||
}
|
||||
|
||||
shm->data = (shared_t*)mmap(0,shm->datasize,
|
||||
PROT_READ | PROT_WRITE,
|
||||
COVERAGE_MAP_FLAGS,
|
||||
shm->datafd,0);
|
||||
|
||||
if ((long)shm->data == -1) {
|
||||
RtiError("failed to map data, (%d)\n",errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
shm->arrayhead = (sharray_t*)shm->data;
|
||||
|
||||
CoverageShmUnlock(shm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* Look for more arrays
|
||||
* return values
|
||||
* -1 - remap failed, arrays no longer valid
|
||||
* 0 - no change in mapping
|
||||
* 1 - arrays have been remapped, update arrays
|
||||
*/
|
||||
int CoverageShmRemap(shmregion_t *shm)
|
||||
{
|
||||
struct stat s;
|
||||
int rval = 0;
|
||||
sharray_t *newhead;
|
||||
shared_t *oldbase;
|
||||
|
||||
RtiDebug("enter\n");
|
||||
|
||||
CoverageShmLock(shm);
|
||||
|
||||
if (shm->meta->n_arrays == shm->n_arrays) {
|
||||
CoverageShmUnlock(shm);
|
||||
shm->n_arrays_new = 0;
|
||||
RtiDebug("no change (%d arrays), exit\n",shm->n_arrays);
|
||||
return rval;
|
||||
}
|
||||
|
||||
fstat(shm->datafd,&s);
|
||||
|
||||
if (s.st_size > shm->datasize) {
|
||||
oldbase = shm->data;
|
||||
RtiInfo("resizing from %d to %d bytes, old base = %p\n",shm->datasize,(int)s.st_size,shm->data);
|
||||
munmap(shm->data,shm->datasize);
|
||||
shm->data = (shared_t*)mmap(shm->data,
|
||||
s.st_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
COVERAGE_MAP_FLAGS,
|
||||
shm->datafd,0);
|
||||
|
||||
/* TODO: Check if I really need this. If mmap can place it at the given address
|
||||
* it will automatically place it somewhere else I think. Need to check this
|
||||
* (tron).
|
||||
*/
|
||||
if ((long)shm->data == -1) {
|
||||
RtiError("Failed to remap at existing area, trying another place...\n");
|
||||
shm->data = (shared_t*)mmap(0,
|
||||
s.st_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
COVERAGE_MAP_FLAGS,
|
||||
shm->datafd,0);
|
||||
if ((long)shm->data == -1) {
|
||||
RtiError("Failed to remap, not all data will be read from this file ...\n");
|
||||
shm->data = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* NOTE: The array may move even when we specify an address (tron) */
|
||||
if (shm->data != oldbase) {
|
||||
rval = 1;
|
||||
shm->arrayhead = (sharray_t*)shm->data;
|
||||
shm->n_arrays = 0;
|
||||
}
|
||||
shm->datasize = s.st_size;
|
||||
RtiDebug("base = %p\n",shm->data);
|
||||
}
|
||||
|
||||
newhead = last_array(shm);
|
||||
|
||||
CoverageShmUnlock(shm);
|
||||
|
||||
shm->n_arrays_new = shm->n_arrays;
|
||||
|
||||
if (newhead != shm->arrayhead) {
|
||||
CoverageShmArrayAdd(shm,newhead);
|
||||
}
|
||||
|
||||
shm->n_arrays_new = shm->n_arrays - shm->n_arrays_new;
|
||||
|
||||
RtiInfo("change (%d) arrays, exit\n",shm->n_arrays_new);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* Initialise a an existing shm region
|
||||
*/
|
||||
shmregion_t *CoverageShmInit(shmregion_t *shm, const char * const filename,
|
||||
int fc, int datasize, int increment)
|
||||
{
|
||||
if (!CoverageShmInitInternal(shm,filename,fc,datasize,increment))
|
||||
return shm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* Delete resources used by a shm, but do not delete the
|
||||
* region itself
|
||||
*/
|
||||
int CoverageShmDelete(shmregion_t *shm)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
RtiDebug("enter\n");
|
||||
if (munmap(shm->meta,sizeof(struct shared_t))) {
|
||||
RtiError("Failed to unmap meta, (%d)\n",errno);
|
||||
err++;
|
||||
}
|
||||
/* shm->data may have been set 0 if a remap failed */
|
||||
if (shm->data && munmap(shm->data,shm->datasize)) {
|
||||
RtiError("Failed to unmap data, (%d)\n",errno);
|
||||
err++;
|
||||
}
|
||||
free(shm->datafile);
|
||||
free(shm->lockfile);
|
||||
|
||||
/* TODO: a fd to the datafile is kept open for the duration
|
||||
* of the run. Might open/close as needed in the future
|
||||
*/
|
||||
if (close(shm->datafd)) {
|
||||
RtiError("Failed to close datafile, (%d)\n",errno);
|
||||
err++;
|
||||
}
|
||||
RtiDebug("exit\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* Allocates a new shm region
|
||||
*/
|
||||
shmregion_t *CoverageShmCreate(const char * const filename, int fc,
|
||||
int datasize, int increment)
|
||||
{
|
||||
shmregion_t *shm;
|
||||
|
||||
shm = (shmregion_t*)malloc(sizeof(struct shmregion_t));
|
||||
if (shm == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (!CoverageShmInitInternal(shm,filename,fc,datasize,increment))
|
||||
return shm;
|
||||
|
||||
free(shm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* Destroys a shm region, deleting all resources associated with it
|
||||
* and freeing shm
|
||||
*/
|
||||
int CoverageShmDestroy(shmregion_t *shm)
|
||||
{
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/* symfind.c - Find symbol */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
-------------------
|
||||
01d,12oct13,wzc Fix prevent warnings.
|
||||
01c,29jun12,wzc WIND00350881 - check malloc return value.
|
||||
01b,10feb10,flu Change code for 64-bit porting.
|
||||
01a,27jul09,jfu Clear existing coverage data via
|
||||
RESET_ALL_COVERAGE_ARRAYS/RESET_ALL_COVERAGE_ARRAYS
|
||||
commands for requirement 170416
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
1.0 Nov19 2001, created
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Find symbol.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef RTI_VXWORKS
|
||||
# include <vxWorks.h>
|
||||
# include <a_out.h>
|
||||
# include <symLib.h>
|
||||
# include <sysSymTbl.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <rtilib/rti_syserr.h>
|
||||
#include "coveragedata.pkg.h"
|
||||
#include "coveragenet.pkg.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#pragma begin_package
|
||||
/*- local strdup implementation so as not to load libutilsxx.so library -*/
|
||||
// TD: most current clients of this function probably don't need a copy of
|
||||
// the string they're working with, eliminate gratuitous use of STRDUP.
|
||||
static inline
|
||||
char *STRDUP(const char * const s)
|
||||
{
|
||||
size_t len;
|
||||
char *str;
|
||||
if (!s) return 0;
|
||||
|
||||
len = strlen(s) + 1;
|
||||
str = malloc(len);
|
||||
if (!str) return 0;
|
||||
return memcpy(str, s, len);
|
||||
}
|
||||
|
||||
#pragma end_package
|
||||
|
||||
|
||||
//TD: this is strtok or strsep
|
||||
char* mystrsplit(char* s, char delim, char** ppLast)
|
||||
{
|
||||
char* strEnd=s;
|
||||
|
||||
if (s == NULL) {
|
||||
s = *ppLast;
|
||||
}
|
||||
|
||||
if (s != NULL) {
|
||||
strEnd=strchr(s,delim);
|
||||
if (strEnd != NULL) {
|
||||
*strEnd='\0';
|
||||
*ppLast=strEnd+1;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the number of arrays from a colon (:) separated list
|
||||
* of array names
|
||||
*/
|
||||
Peer
|
||||
int findNumArrays(const char* const nameList)
|
||||
{
|
||||
const char* tmpNameList;
|
||||
int count=1;
|
||||
for (tmpNameList=nameList;*tmpNameList!='\0';tmpNameList++)
|
||||
{
|
||||
if (*tmpNameList == ':')
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* We could have a potentially large number of arrays..
|
||||
* eg. 1000 arrays with names of 32 bytes each = 32K long string
|
||||
* This means we need a 32K buffer to store the XML command before
|
||||
* we can parse it.
|
||||
* We can either
|
||||
* i)Send the entire data in one shot and make sure we somehow
|
||||
* are able to handle it
|
||||
* ii) Send the data in pieces
|
||||
* We choose the option (ii) because:
|
||||
* i) Option 1 is anyway hackish. Has unbounded memory requirements,
|
||||
* (though it still would be <100k)
|
||||
* ii)Using option 2 we can add arrays for collection on the target
|
||||
* side as and when needed. Each request to add an array would
|
||||
* be an independent command. We would simply add to the
|
||||
* existing book-keeping records. The overhead would be to realloc
|
||||
* memory
|
||||
*
|
||||
* The host could send the array list in batches if the size is too
|
||||
* big. This also allows the host to update the array list with time
|
||||
* without having to send the entire array list
|
||||
*
|
||||
* IMPORTANT NOTE: this function is defined twice, once for WTX mode
|
||||
* and once for tcp/ip mode
|
||||
*/
|
||||
|
||||
Peer
|
||||
int findAllArraysByName(char* nameList,CoverageDaemonInfo* pCoverage)
|
||||
{
|
||||
char* arrayName=NULL;
|
||||
char* arrayStr = NULL;
|
||||
int index;
|
||||
int count=0;
|
||||
int numArrays;
|
||||
char* ppLast=NULL;
|
||||
int numArraysAddrs;
|
||||
|
||||
/*-----Now get info for new data list-----------*/
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("finding all arrays: %s\n",nameList);
|
||||
|
||||
numArraysAddrs=findNumArrays(nameList);
|
||||
numArrays=(numArraysAddrs/3);
|
||||
|
||||
count=numArrays;
|
||||
index=pCoverage->numArrays;
|
||||
pCoverage->numArrays+=numArrays;
|
||||
|
||||
if (pCoverage->debugLevel>2)
|
||||
printf("numArrays:%d pCov->numArray:%d index:%d\n",numArrays,
|
||||
pCoverage->numArrays,index);
|
||||
|
||||
if (pCoverage->numArrays==numArrays)
|
||||
{
|
||||
pCoverage->pCoverageArray=(int**)malloc(numArrays*sizeof(int*));
|
||||
pCoverage->coverageArrayNames=(char**)malloc(numArrays*sizeof(char*));
|
||||
pCoverage->coverageArrayPdId=(RTP_ID*)malloc(numArrays*sizeof(long));
|
||||
if ((pCoverage->pCoverageArray == NULL) ||
|
||||
(pCoverage->coverageArrayNames == NULL)||
|
||||
(pCoverage->coverageArrayPdId == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pCoverage->pCoverageArray=(int**)realloc(pCoverage->pCoverageArray,
|
||||
pCoverage->numArrays*sizeof(int*));
|
||||
pCoverage->coverageArrayNames=(char**)
|
||||
realloc(pCoverage->coverageArrayNames,pCoverage->numArrays*sizeof(char*));
|
||||
pCoverage->coverageArrayPdId=(RTP_ID*)
|
||||
realloc(pCoverage->coverageArrayPdId, pCoverage->numArrays*sizeof(long));
|
||||
if ((pCoverage->pCoverageArray == NULL) ||
|
||||
(pCoverage->coverageArrayNames == NULL)||
|
||||
(pCoverage->coverageArrayPdId == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (count==numArrays)
|
||||
arrayName=mystrsplit(nameList,':',&ppLast);
|
||||
else
|
||||
arrayName=mystrsplit(NULL,':',&ppLast);
|
||||
|
||||
/*Find the symbol address*/
|
||||
if (pCoverage->debugLevel>2)
|
||||
printf("Finding array:%s\n",arrayName);
|
||||
|
||||
|
||||
/* Set the address and names of coverage Arrays */
|
||||
/* Some entries for symbol address might be NULL */
|
||||
/* In TCP/IP mode, all addresses will be known when sent to the target */
|
||||
pCoverage->coverageArrayNames[index] = STRDUP(arrayName);
|
||||
|
||||
if ((arrayStr = mystrsplit(NULL,':',&ppLast)) != NULL)
|
||||
pCoverage->coverageArrayPdId[index] = (RTP_ID) strtoul( (const char*)
|
||||
arrayStr, (char **) NULL, 10);
|
||||
|
||||
if ((arrayStr = mystrsplit(NULL,':',&ppLast)) != NULL)
|
||||
pCoverage->pCoverageArray[index]=(int *) strtoul((const char*)
|
||||
arrayStr, (char **) NULL, 10);
|
||||
|
||||
if (pCoverage->debugLevel>2)
|
||||
{
|
||||
printf("Found Symbol :%s id: 0x%lx address:%p\n",
|
||||
pCoverage->coverageArrayNames[index],
|
||||
(unsigned long) pCoverage->coverageArrayPdId[index],
|
||||
pCoverage->pCoverageArray[index]);
|
||||
}
|
||||
/*warning!!! strdup does a malloc*/
|
||||
count--;
|
||||
index++;
|
||||
} while (count>0);
|
||||
if (pCoverage->debugLevel>1)
|
||||
printf("+_+_+_Done with find all arrays\n");
|
||||
return numArrays;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/* symfind.pkg.h - built from: symfind.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef symfind_pkg_h
|
||||
#define symfind_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*- local strdup implementation so as not to load libutilsxx.so library -*/
|
||||
// TD: most current clients of this function probably don't need a copy of
|
||||
// the string they're working with, eliminate gratuitous use of STRDUP.
|
||||
static inline
|
||||
char *STRDUP(const char * const s)
|
||||
{
|
||||
size_t len;
|
||||
char *str;
|
||||
if (!s) return 0;
|
||||
|
||||
len = strlen(s) + 1;
|
||||
str = malloc(len);
|
||||
if (!str) return 0;
|
||||
return memcpy(str, s, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern int findNumArrays(const char* const nameList);
|
||||
|
||||
|
||||
extern int findAllArraysByName(char* nameList,CoverageDaemonInfo* pCoverage);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* symfind_pkg_h */
|
||||
@@ -0,0 +1,72 @@
|
||||
/* utils.c - Load a module on the target */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01b,10feb10,flu Remove obsolete code for 64-bit porting.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Load a module on the target
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
|
||||
|
||||
#include "coveragedata.pkg.h"
|
||||
/*
|
||||
* Function to load a module on the target
|
||||
* Need loadlib to work directly on the target.
|
||||
* return values : NULL on failure
|
||||
* MODULE_ID on success
|
||||
*/
|
||||
Peer
|
||||
UINT32 CoverageLoadModuleOnTarget(char* moduleName, int debugLevel, char* returnMsg)
|
||||
{
|
||||
/* For the time being, since we don't use this part of code, loadedModuleId will
|
||||
be set to 0 */
|
||||
// MODULE_ID loadedModuleId=0;
|
||||
|
||||
/* For a VxWorks kernel without a symbol table, use of loadModule generates
|
||||
undefined symbol warning. Since, this code is not used, it will removed for
|
||||
now */
|
||||
#if 0
|
||||
int fdX=open(moduleName,O_RDONLY,0644);
|
||||
if (fdX<0){
|
||||
CoverageV1Warning(debugLevel)
|
||||
("Could not locate module :%s\n",moduleName);
|
||||
sprintf(returnMsg,"Failed to open module:%s\n",moduleName);
|
||||
return 0;
|
||||
}
|
||||
loadedModuleId=loadModule(fdX,LOAD_ALL_SYMBOLS);
|
||||
if (loadedModuleId==NULL){
|
||||
CoverageV1Warning(debugLevel)
|
||||
("Failed to load module %s\n",moduleName);
|
||||
sprintf(returnMsg,"Failed to load:module:%s\n",moduleName);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
CoverageV2Warning(debugLevel)
|
||||
("Successfully loaded module :%s\n",moduleName);
|
||||
sprintf(returnMsg,"Loading successful:%s\n",moduleName);
|
||||
}
|
||||
close(fdX);
|
||||
#endif
|
||||
// return (UINT32)loadedModuleId;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* utils.pkg.h - built from: utils.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef utils_pkg_h
|
||||
#define utils_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern UINT32 CoverageLoadModuleOnTarget(char* moduleName, int debugLevel, char* returnMsg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* utils_pkg_h */
|
||||
@@ -0,0 +1,80 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,20jul12,wzc WIND00357415 - remove building warnings.
|
||||
# 01a,14oct10,vhe Fixed passing of SDA_DISABLE to sub-make (CQ:WIND000236260)
|
||||
# 01d,15jul09,??? Modify for Requirement WIND119168
|
||||
# 01c,19aug08,tcr update version
|
||||
# 01b,09jul08,c_c Reworked Tool search.
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# These are rules and definitions that are used throughout most of the other
|
||||
# ScopeTools Makefiles.
|
||||
#
|
||||
#*/
|
||||
|
||||
|
||||
# Common definitions needed by most of the tool code.
|
||||
EXTRA_DEFINE += -D__PROTOTYPE_5_0 -DRTI_VXWORKS
|
||||
|
||||
|
||||
# We need to filter out any small data enabling switches, since the DKM loader
|
||||
# doesn't support them yet.
|
||||
export SDA_DISABLE = true
|
||||
|
||||
# defs.library to pull in automatic definition of the VX_CPU_FAMILY and TOOL,
|
||||
# based on the value of CPU.
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
|
||||
# create an analysis subdirectory for our objects and libs.
|
||||
LIBDIRBASE = $(VX_CPU_FAMILY)$(ARCH_OPTION_SUFFIX)/$(CPU)$(CPU_OPTION_SUFFIX)/$(TOOL_COMMON_DIR)$(LIB_DIR_TAG)$(MINOR_OPTION_SUFFIX)/analysis
|
||||
|
||||
# create a subtree for our generated DKM objects.
|
||||
DKMDIRBASE = $(VX_CPU_FAMILY)$(ARCH_OPTION_SUFFIX)/$(CPU)$(CPU_OPTION_SUFFIX)/$(TOOL_COMMON_DIR)$(LIB_DIR_TAG)$(MINOR_OPTION_SUFFIX)/dkm/analysis
|
||||
|
||||
##
|
||||
# Add toolchain specific switches
|
||||
#
|
||||
|
||||
ifneq (, $(findstring diab,$(TOOL)))
|
||||
# Enables the "inline" keyword
|
||||
# ignores unknown pragma warnings
|
||||
# ignores unknown pragma warnings (1560 for C, 4161 for C++)
|
||||
CFLAGS += -Xkeywords=4 -ei1560,4161,5659
|
||||
endif
|
||||
|
||||
|
||||
ifneq (, $(findstring gnu,$(TOOL)))
|
||||
# ignores unknown pragma warnings
|
||||
CFLAGS += -Wno-unknown-pragmas
|
||||
endif
|
||||
|
||||
|
||||
# This should be migrated to a more common location.
|
||||
ifeq (ppc,$(VX_CPU_FAMILY))
|
||||
LONGCALL = -mlongcall
|
||||
endif
|
||||
|
||||
# needed for DKM-capable objects
|
||||
CFLAGS += $(LONGCALL)
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
include $(TOOLS_SRC_ROOT)/make/header.mk
|
||||
|
||||
# build headers before compiling anything
|
||||
ifeq ($(ENABLE_HEADER_GENERATION),1)
|
||||
$(LIBOBJS): $(PKG_H) $(HEADERS)
|
||||
endif
|
||||
|
||||
# The source currently uses some non-ansi comments, make sure these don't cause
|
||||
# compilation errors.
|
||||
CFLAGS_ANSI = $(filter-out -ansi, $(CFLAGS))
|
||||
CFLAGS := $(CFLAGS_ANSI)
|
||||
|
||||
|
||||
# rule to build the DKM output directory, if needed
|
||||
$(LIB_ROOT)/$(DKMDIRBASE):
|
||||
@$(MKDIR) $(LIB_ROOT)/$(DKMDIRBASE)
|
||||
@@ -0,0 +1,42 @@
|
||||
#############################################################################
|
||||
#
|
||||
# header.mk
|
||||
#
|
||||
# modification history
|
||||
# ------------ -------
|
||||
# 01b,15jul09,??? Modify for Requirement WIND119168
|
||||
# 01a,26mar08,pca written.
|
||||
#
|
||||
# Used to generate header files. Set MHFLAGS to -f to force write of .h file
|
||||
|
||||
MAKEHEADER = $(TOOLS_SRC_ROOT)/make/makeheader/$(WIND_HOST_TYPE)/makeheader
|
||||
|
||||
MAKEHEADERPKGKEYS = -k public -k peer -k package -k Public -k Peer -k Package
|
||||
|
||||
ifneq ($(wildcard $(MAKEHEADER)*),)
|
||||
ENABLE_HEADER_GENERATION =1
|
||||
else
|
||||
ENABLE_HEADER_GENERATION =0
|
||||
endif
|
||||
|
||||
MAKEHEADER := $(MAKEHEADER) $(MHFLAGS)
|
||||
|
||||
ifeq ($(ENABLE_HEADER_GENERATION),1)
|
||||
LOCAL_CLEAN = *.pkg.h $(HEADERS)
|
||||
|
||||
%.pkg.h: %.c
|
||||
$(MAKEHEADER) $(MAKEHEADERPKGKEYS) -C $< -o $@
|
||||
|
||||
|
||||
# The headers goal explicitly forces generation of package and public headers.
|
||||
# Normally this is taken care of implicitly during compilation, but the higher-
|
||||
# level build rules rely on generating headers before starting the compilation
|
||||
# to deal with some ordering issues.
|
||||
.PHONY: headers
|
||||
headers: $(PKG_H) $(HEADERS)
|
||||
|
||||
ifneq (,$(SUBDIRS))
|
||||
$(MAKE) TARGET=headers $(SUBDIRS)
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Makefile - makefile for building MemScope
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,26mar08,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the rti library
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ..
|
||||
|
||||
DOC_FILES =
|
||||
|
||||
LIB_BASE_NAME =
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
DKMS = $(LIB_ROOT)/$(DKMDIRBASE)/memscope.so
|
||||
MEMSCOPE_OBJS = $(LIB_ROOT)/$(LIBDIRBASE)/objmemscope/*.o
|
||||
|
||||
.PHONY: dkms
|
||||
|
||||
dkms: $(DKMS)
|
||||
|
||||
$(LIB_ROOT)/$(DKMDIRBASE)/memscope.so: $(MEMSCOPE_OBJS)
|
||||
$(LD_PARTIAL) $^ -o $@
|
||||
|
||||
LOCAL_CLEAN += $(DKMS)
|
||||
@@ -0,0 +1,31 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,26mar06,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../..
|
||||
|
||||
LIB_BASE_NAME = memscope
|
||||
|
||||
EXTRA_DEFINE += -DMEMSCOPEVERSION=\"3.7a\"
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/rtilib/include/vx \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include/vx \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/context \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= memlinkcomm.o
|
||||
PKG_H=
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
# end of memscope/comm
|
||||
@@ -0,0 +1,967 @@
|
||||
/* memlinkcomm.c - common MemScope link code */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002-2011, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
------------ -------
|
||||
01h,12oct13,wzc Fix prevent warnings.
|
||||
01g,24jun13,wzc Fix prevent warnings.(WIND00422900)
|
||||
01f,02mar11,wzc Enlarge the size of message size.(WIND00252117)
|
||||
01e,12jun10,wzc Exit MA when network failed. (WIND00204254).
|
||||
01d,03sep09,??? For defect 177116, changed for function patch
|
||||
01c, 23jul09,wzc Change copyright notice and module layout.
|
||||
01b, 06jul09,wzc Fix Coverity Prevent error
|
||||
01a,15jul09,??? Modify for Requirement WIND119168
|
||||
30c, 07nov02,pca ported to AE
|
||||
30a, 18mar02,pca Updated to work with rtilib.4.2
|
||||
30a, 18feb02,pca Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Common MemScope link code.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <eventsxml.h>
|
||||
#include <errno.h>
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#pragma begin_package
|
||||
#include <rtilib/rti_tcp.h>
|
||||
#include <rtilib/rti_osapi.h>
|
||||
#pragma end_package
|
||||
|
||||
/* defines */
|
||||
|
||||
#if defined(RTI_WIN32)
|
||||
/* visual studio doesn't provide snprintf() */
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
//TD: share these with memscope.c
|
||||
#define ENDOFSTACK ((void *) -1)
|
||||
|
||||
// TD: Describe all defines
|
||||
#define MEMSCOPE_DEBUG_MEMLINK (0)
|
||||
|
||||
#define MEMSCOPE_MAX_BLOCKS (20) /* for HeapGetPoolBlocks */
|
||||
|
||||
#define MAX_MEMLINK_CALLBACKS (20)
|
||||
#define MAX_MEMLINK_MSG_LEN (750)
|
||||
|
||||
/* delay timings in nanoseconds */
|
||||
#define CONNECTION_RETRY_DELAY (20000000)
|
||||
#define BUSY_CONNECTION_DELAY (20000000)
|
||||
|
||||
/*-- Used for MemLinkPatchCommon --*/
|
||||
/* Defines for alloc / free installation */
|
||||
#define TAG_ID "IDENTIFIER"
|
||||
#define TAG_PARTID "PARTID"
|
||||
#define TAG_AMOUNT "AMOUNT"
|
||||
#define TAG_FLOAT "FLOAT"
|
||||
#define TAG_DOUBLE "DOUBLE"
|
||||
#define TAG_NONFLOAT "NONFLOAT"
|
||||
#define TAG_NONFLOATDOUBLE "NONFLOATDOUBLE"
|
||||
#define TAG_SUCCESS "SUCCESS"
|
||||
#define TAG_IGNORE "IGNORE"
|
||||
|
||||
/* Define max connect error times --*/
|
||||
#define MAX_CONNECT_ERROR (10)
|
||||
|
||||
#pragma begin_package
|
||||
#define MEMLINK_PARAM_STRING_LEN (32) /* max parameter creation string length */
|
||||
#pragma end_package
|
||||
|
||||
/*-- --*/
|
||||
|
||||
|
||||
// TD: make these accurate
|
||||
#pragma begin_package
|
||||
#define MAX_COMMAND_LENGTH (1024)
|
||||
#pragma end_package
|
||||
|
||||
|
||||
#pragma begin_package
|
||||
/***************************************
|
||||
* Commands
|
||||
*/
|
||||
#define SHUTDOWN ("Shutdown")
|
||||
#define TAG_FREE_TRUE ("FREE_TAGGING_TRUE")
|
||||
#define TAG_FREE_FALSE ("FREE_TAGGING_FALSE")
|
||||
#define MEMPART_OPTIONS_SET ("MEMPART_SET_OPTIONS")
|
||||
#define HEAP_CHECK_INSTALL ("HEAP_CHECK_INSTALL")
|
||||
#define HEAP_CHECK_REMOVE ("HEAP_CHECK_REMOVE")
|
||||
#define MEM_PATCH_INSTALL ("MEM_PATCH_INSTALL")
|
||||
#define MEM_PATCH_REMOVE ("MEM_PATCH_REMOVE")
|
||||
#define MEM_HEAP_SEND ("MEM_HEAP_SEND")
|
||||
#define MEM_COLLECTION_ENABLE ("MEM_COLLECTION_ENABLE")
|
||||
#define MEM_COLLECTION_DISABLE ("MEM_COLLECTION_DISABLE")
|
||||
#define PING ("ping")
|
||||
|
||||
|
||||
typedef enum {
|
||||
RUNNING,
|
||||
DONE
|
||||
} ThreadStatus;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void * xmlEngine;
|
||||
RTITcp* tcpLink;
|
||||
char cmdBuff[MAX_COMMAND_LENGTH];
|
||||
unsigned int cmdStartPosition;
|
||||
RTIBool shouldExit;
|
||||
ThreadStatus status;
|
||||
RTINtpTime pollDelay;
|
||||
} Link;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
int paramNumPartId;
|
||||
int paramNumIdentifier;
|
||||
int paramNumAmount;
|
||||
char paramString[MEMLINK_PARAM_STRING_LEN];
|
||||
} MemLinkAllocData;
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
int paramNumPartId;
|
||||
int paramNumIdentifier;
|
||||
char paramString[MEMLINK_PARAM_STRING_LEN];
|
||||
} MemLinkFreeData;
|
||||
|
||||
|
||||
#pragma end_package
|
||||
|
||||
|
||||
// TD: Is this the best way to handle this, should we include these from
|
||||
// a header?
|
||||
extern RTIBool MemLinkSendInitialData(Link * const link);
|
||||
extern RTIBool MemLinkRecordsSend(Link * const link);
|
||||
extern RTIBool MemLinkCheckOverflows(Link * const link);
|
||||
extern void MemScopeTargetExit(void);
|
||||
|
||||
|
||||
#if MEMSCOPE_DEBUG_MEMLINK
|
||||
Package
|
||||
/**
|
||||
* Debugging call which dumps everything we know
|
||||
* about the Link object.
|
||||
**/
|
||||
void dumpLink(const Link * const link)
|
||||
{
|
||||
RtiMessage("Link:\t%p\n", link);
|
||||
RtiMessage("\txml engine:\t%p\n", link->xmlEngine);
|
||||
RtiMessage("\tcmdStartPosition:\t%i\n", link->cmdStartPosition);
|
||||
RtiMessage("\tshouldExit:\t%i\n", link->shouldExit);
|
||||
RtiMessage("\tTcp link:\t%p\n", link->tcpLink);
|
||||
RtiMessage("\t\thost:\t%s\n", link->tcpLink->HostNameGet(link->tcpLink));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Create a link object.
|
||||
* This will open a socket for listening and warm up the XML
|
||||
* parser.
|
||||
*/
|
||||
RTIBool LinkCreate(Link * const link, const unsigned int port,
|
||||
const unsigned int delay)
|
||||
{
|
||||
if (!RtiNetioInit()) {
|
||||
RtiMessage("Error initializing RTI net libs.\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
link->xmlEngine = XMLInit(MAX_MEMLINK_CALLBACKS);
|
||||
if (link->xmlEngine == 0) {
|
||||
RtiMessage("Failed to initialize XML engine.\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if ( link->tcpLink == 0 ) {
|
||||
link->tcpLink = RtiTcpNew(RTI_TCP_SERVER, port, RTI_TCP_REUSEPORT);
|
||||
if (link->tcpLink == 0) {
|
||||
RtiMessage("Failed to open socket.\n");
|
||||
XMLClose(link->xmlEngine);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
link->tcpLink->ListenBlockingSet(link->tcpLink, RTI_NETIO_NONBLOCKING);
|
||||
link->tcpLink->DataBlockingSet(link->tcpLink, RTI_NETIO_NONBLOCKING);
|
||||
}
|
||||
|
||||
link->cmdStartPosition = 0;
|
||||
link->shouldExit = RTI_FALSE;
|
||||
RtiNtpTimePackFromNanosec(link->pollDelay, 0, delay);
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/**
|
||||
* Check for incomming data on our socket
|
||||
* and attempt to parse it as a command.
|
||||
*/
|
||||
RTIBool LinkCommandReceive(Link * const link)
|
||||
{
|
||||
char readBuff[MAX_COMMAND_LENGTH];
|
||||
int readLength;
|
||||
|
||||
//bzero(readBuff,READ_BUFSIZE);
|
||||
if (link->tcpLink == 0) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
readLength = link->tcpLink->Read(link->tcpLink,
|
||||
readBuff, MAX_COMMAND_LENGTH);
|
||||
|
||||
if (readLength == RTI_NETIO_ERROR) {
|
||||
RtiMessage("Error reading commands.\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
//RtiMessage("Read: %i\n", readLength);
|
||||
|
||||
if (readLength == 0) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
RtiMessage("\t%p\n", link);
|
||||
RtiMessage("\t%p\n", link->tcpLink);
|
||||
RtiMessage("\t%p\n", readBuff);
|
||||
RtiMessage("\t%i\n", MAX_COMMAND_LENGTH);
|
||||
RtiMessage("\t%s\n", readBuff);
|
||||
}
|
||||
|
||||
commandParse(link->cmdBuff, readBuff, readLength,
|
||||
&(link->cmdStartPosition), link->xmlEngine);
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
RTIBool LinkDataSend( const Link * const link, const char * data,
|
||||
unsigned int size)
|
||||
{
|
||||
RTINtpTime busyConnectionDelay;
|
||||
RtiNtpTimePackFromNanosec(busyConnectionDelay, 0, BUSY_CONNECTION_DELAY);
|
||||
|
||||
if( size == 0 ) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
if (link->tcpLink == 0) {
|
||||
RtiMessage("Sending while unconnected!\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
const int bytesSent =
|
||||
link->tcpLink->Writen(link->tcpLink, (char *)data, size);
|
||||
|
||||
if( (unsigned int)bytesSent == size) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
if(bytesSent < 0) {
|
||||
/* write error */
|
||||
const int err = RtiNetioErrnoGet();
|
||||
switch (err) {
|
||||
case EWOULDBLOCK:
|
||||
RtiMessage("Link ERROR: Operation would block\n");
|
||||
break;
|
||||
case EPFNOSUPPORT:
|
||||
RtiMessage("Link ERROR: protocol not supported\n");
|
||||
break;
|
||||
case ENOTSOCK:
|
||||
RtiMessage("Link ERROR: operation on non-scocket\n");
|
||||
break;
|
||||
case EADDRINUSE:
|
||||
RtiMessage("Link ERROR: address already in use\n");
|
||||
break;
|
||||
case EINTR:
|
||||
RtiMessage("Link ERROR: interrupted system call\n");
|
||||
break;
|
||||
case EISCONN:
|
||||
RtiMessage("Link ERROR: is already connected\n");
|
||||
break;
|
||||
case EALREADY:
|
||||
RtiMessage("Link ERROR: operation already in progress\n");
|
||||
break;
|
||||
case EINPROGRESS:
|
||||
RtiMessage("Link ERROR: operation now in progress\n");
|
||||
break;
|
||||
case ECONNREFUSED:
|
||||
RtiMessage("Link ERROR: connection refused\n");
|
||||
break;
|
||||
case EMSGSIZE:
|
||||
RtiMessage("Link ERROR: message size\n");
|
||||
break;
|
||||
case EPIPE:
|
||||
RtiMessage("Link ERROR: Broken Pipe\n");
|
||||
//LinkDestroy(link);
|
||||
break;
|
||||
default:
|
||||
RtiMessage("UNKNOWN LINK ERROR: %i.\n", err);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
|
||||
} else if(bytesSent == 0) {
|
||||
/* RtiMessage("MemScopeDataSend: 0 bytes sent!\n"); */
|
||||
RtiThreadSleep(&busyConnectionDelay);
|
||||
} else {
|
||||
/* modify size and pointer for next try */
|
||||
size -= bytesSent;
|
||||
data += bytesSent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Inform the host of the target version.
|
||||
**/
|
||||
RTIBool MemLinkVersionSend(const unsigned int systemPartition,
|
||||
const unsigned int memoryTop,
|
||||
const unsigned int kernelPdId,
|
||||
const RTIBool patchCapable,
|
||||
const RTIBool poolFindCapable,
|
||||
const Link * const link)
|
||||
{
|
||||
#define MAX_VERSION_LENGTH (256)
|
||||
|
||||
char buf[MAX_VERSION_LENGTH];
|
||||
|
||||
const int len = snprintf(buf, MAX_VERSION_LENGTH,
|
||||
"<Connect"
|
||||
" version=\""
|
||||
MEMSCOPEVERSION
|
||||
"\""
|
||||
" sysPartition=\"%x\""
|
||||
" sysMemTop=\"%x\""
|
||||
" kernelPdId=\"%x\""
|
||||
" patchCapable=\"%s\""
|
||||
" poolFindCapable=\"%s\""
|
||||
"></Connect>",
|
||||
systemPartition,
|
||||
memoryTop,
|
||||
kernelPdId,
|
||||
patchCapable ? "TRUE" : "FALSE",
|
||||
poolFindCapable ? "TRUE" : "FALSE");
|
||||
|
||||
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("sent\t%s\n",buf);
|
||||
}
|
||||
|
||||
return LinkDataSend(link, buf, len);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Sends a record of a pre-allocated heap block
|
||||
**/
|
||||
void MemLinkHeapBlockSend(const unsigned int blockStart,
|
||||
const unsigned int size,
|
||||
const Link * const link)
|
||||
{
|
||||
char buf[65]; /* <block start="0x%016x" length="0x%016x" /> */
|
||||
|
||||
snprintf(buf,sizeof(buf),
|
||||
"<used-block start=\"%x\" "
|
||||
"length=\"%x\"></used-block>",
|
||||
blockStart,size);
|
||||
//RtiMessage("%s\n", buf);
|
||||
LinkDataSend(link, buf, strlen(buf));
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
RTIBool MemLinkAllocSend(const unsigned int data[],
|
||||
const char * const taskName,
|
||||
const unsigned int stackDepth,
|
||||
const Link * const link)
|
||||
{
|
||||
char buf[MAX_MEMLINK_MSG_LEN];
|
||||
unsigned int i;
|
||||
|
||||
int size =
|
||||
snprintf(buf, sizeof(buf),
|
||||
"<Alloc"
|
||||
" partitionID=\"%x\"\n"
|
||||
" address=\"%x\"\n"
|
||||
" numBytes=\"%x\"\n"
|
||||
" tid=\"%x\"\n"
|
||||
" pid=\"%x\"\n"
|
||||
" grp=\"%x\"\n"
|
||||
" taskName=\"%s\"\n"
|
||||
" callStack=\"",
|
||||
data[0],
|
||||
data[1],
|
||||
data[2],
|
||||
data[3],
|
||||
data[4],
|
||||
data[5],
|
||||
taskName);
|
||||
|
||||
/* Now format that pesky call stack */
|
||||
|
||||
for (i=0; i < stackDepth; i++){
|
||||
const unsigned int address = ((int *)data)[6 + i];
|
||||
|
||||
if ( (void *)address == ENDOFSTACK ) {
|
||||
break;
|
||||
}
|
||||
size += snprintf( (buf+size), sizeof(buf) - size,
|
||||
"%x ", address);
|
||||
}
|
||||
|
||||
/* Remove extra space from the end of buffer */
|
||||
size--;
|
||||
|
||||
/* Close out all tags */
|
||||
size+= snprintf( (buf + size),sizeof(buf) - size,
|
||||
"\"></Alloc>");
|
||||
|
||||
// logMsg("%s\n", buf);
|
||||
return LinkDataSend(link, buf, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
RTIBool MemLinkFreeSend(const unsigned int data[],
|
||||
const char * const taskName,
|
||||
const unsigned int stackDepth,
|
||||
const Link * const link)
|
||||
{
|
||||
char buf[MAX_MEMLINK_MSG_LEN];
|
||||
unsigned i;
|
||||
|
||||
int size =
|
||||
snprintf(buf, sizeof(buf),
|
||||
"<Free"
|
||||
" partitionID=\"%x\"\n"
|
||||
" address=\"%x\"\n"
|
||||
" tid=\"%x\"\n"
|
||||
" pid=\"%x\"\n"
|
||||
" grp=\"%x\"\n"
|
||||
" taskName=\"%s\"\n"
|
||||
" callStack=\"",
|
||||
data[0],
|
||||
data[1],
|
||||
data[3],
|
||||
data[4],
|
||||
data[5],
|
||||
taskName);
|
||||
|
||||
/* Now format that pesky call stack */
|
||||
for (i=0; i < stackDepth; i++){
|
||||
const unsigned int address = ((int *)data)[6 + i];
|
||||
|
||||
if ( (void *)address == ENDOFSTACK ) {
|
||||
break;
|
||||
}
|
||||
|
||||
size += snprintf( (buf+size), sizeof(buf) - size,
|
||||
"%x ", address);
|
||||
}
|
||||
|
||||
/* Remove extra space from the end of buffer */
|
||||
size--;
|
||||
|
||||
/* Close out all tags */
|
||||
size += snprintf( (buf + size), (sizeof(buf) - size),
|
||||
"\"></Free>");
|
||||
|
||||
// printf("Sent:\n\t%s\n", buf);
|
||||
return LinkDataSend(link, buf, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
RTIBool MemLinkCorrelateSend(const Link * const link)
|
||||
{
|
||||
const char * const buf = "<Correlate></Correlate>";
|
||||
return LinkDataSend(link, buf, strlen(buf));
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Send the number of target overflows to the host.
|
||||
*/
|
||||
RTIBool MemLinkOverflowsSend(const unsigned int overflows,
|
||||
const Link * const link)
|
||||
{
|
||||
char buf[64];
|
||||
int size = snprintf(buf,sizeof(buf),
|
||||
"<Overflow times=\"%x\"></Overflow>",
|
||||
overflows);
|
||||
return LinkDataSend(link, buf, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* State machine responsible for maintaining the memlink;
|
||||
* sending data and processing commands
|
||||
*/
|
||||
void MemLinkEngine(Link * const link)
|
||||
{
|
||||
enum {
|
||||
LINK_STATE_CONNECTING,
|
||||
LINK_STATE_DATAPUSH
|
||||
} state = LINK_STATE_CONNECTING;
|
||||
|
||||
int connectError = 0;
|
||||
|
||||
link->status = RUNNING;
|
||||
|
||||
while (link->shouldExit != RTI_TRUE) {
|
||||
switch (state) {
|
||||
case LINK_STATE_CONNECTING:
|
||||
{
|
||||
RTINtpTime connectionRetryDelay;
|
||||
RTITcpConnectStatus connectionStatus;
|
||||
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
RtiMessage(".");
|
||||
}
|
||||
RtiNtpTimePackFromNanosec(connectionRetryDelay,
|
||||
0, CONNECTION_RETRY_DELAY);
|
||||
|
||||
connectionStatus =
|
||||
link->tcpLink->Connect(link->tcpLink,0);
|
||||
|
||||
switch(connectionStatus) {
|
||||
case RTI_TCP_CONNECT_OK:
|
||||
if (MemLinkSendInitialData(link) == RTI_TRUE) {
|
||||
|
||||
state = LINK_STATE_DATAPUSH;
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
RtiMessage("+\n");
|
||||
}
|
||||
}
|
||||
connectError = 0;
|
||||
break;
|
||||
case RTI_TCP_CONNECT_INPROGRESS:
|
||||
RtiThreadSleep(&connectionRetryDelay);
|
||||
break;
|
||||
case RTI_TCP_CONNECT_NOTINHOSTTABLE:
|
||||
RtiMessage("Not in host table\n");
|
||||
connectError++;
|
||||
if (connectError > MAX_CONNECT_ERROR) {
|
||||
RtiMessage("Reconnection failed, Memory Analyzer exiting.\n");
|
||||
link->shouldExit = RTI_TRUE;
|
||||
#if defined(__VXWORKS__)
|
||||
MemScopeTargetExit();
|
||||
#endif
|
||||
}
|
||||
RtiThreadSleep(&connectionRetryDelay);
|
||||
break;
|
||||
case RTI_TCP_CONNECT_REFUSED:
|
||||
RtiMessage("Connection refused\n");
|
||||
connectError++;
|
||||
if (connectError > MAX_CONNECT_ERROR) {
|
||||
RtiMessage("Reconnection failed, Memory Analyzer exiting.\n");
|
||||
link->shouldExit = RTI_TRUE;
|
||||
#if defined(__VXWORKS__)
|
||||
MemScopeTargetExit();
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
RtiThreadSleep(&connectionRetryDelay);
|
||||
break;
|
||||
case RTI_TCP_CONNECT_ERROR:
|
||||
RtiMessage("Problem connecting!\n");
|
||||
connectError++;
|
||||
if (connectError > MAX_CONNECT_ERROR) {
|
||||
RtiMessage("Reconnection failed, Memory Analyzer exiting.\n");
|
||||
link->shouldExit = RTI_TRUE;
|
||||
#if defined(__VXWORKS__)
|
||||
MemScopeTargetExit();
|
||||
#endif
|
||||
}
|
||||
RtiThreadSleep(&connectionRetryDelay);
|
||||
break;
|
||||
default:
|
||||
RtiMessage("Unknown connection status\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LINK_STATE_DATAPUSH:
|
||||
/* Check for commands, then push out some data */
|
||||
{
|
||||
/*
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
RtiMessage("Pushing data...\n");
|
||||
}
|
||||
*/
|
||||
if (MemLinkRecordsSend(link) != RTI_TRUE) {
|
||||
RtiMessage("Error sending records, reconnecting...\n");
|
||||
state = LINK_STATE_CONNECTING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (LinkCommandReceive(link) != RTI_TRUE) {
|
||||
RtiMessage("Error receiving commands, reconnecting...\n");
|
||||
state = LINK_STATE_CONNECTING;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (MemLinkCheckOverflows(link) != RTI_TRUE) {
|
||||
RtiMessage("Error checking overflows, reconnecting...\n");
|
||||
state = LINK_STATE_CONNECTING;
|
||||
break;
|
||||
}
|
||||
|
||||
RtiThreadSleep(&link->pollDelay);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:/* The code is not reachable */
|
||||
{
|
||||
RtiMessage("Unknown link state: %i\n", state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clean up link-related memory and structures */
|
||||
//TD: do we need to close AND destroy? (I don't think so, but Saket
|
||||
// does this in Coverage...)
|
||||
//link->tcpLink->Close(link->tcpLink);
|
||||
RtiTcpDelete(link->tcpLink);
|
||||
link->tcpLink = 0;
|
||||
XMLClose(link->xmlEngine);
|
||||
link->xmlEngine = 0;
|
||||
|
||||
link->status = DONE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Common patch code - to be called from link-specific patch
|
||||
* code to cope with the results.
|
||||
*
|
||||
* Requires the following parameters:
|
||||
* xmlEngine --
|
||||
* MemScopeAllocData - to be populated and returned
|
||||
* MemScopeFreeData - to be populated and returned
|
||||
*
|
||||
* Returns: RTI_TRUE upon success, RTI_FALSE upon failure. In either
|
||||
* case, values stored in allocData and freeData have been altered.
|
||||
*
|
||||
*
|
||||
* Installs the requested functions as malloc/free replacements
|
||||
* Expects the following parameters:
|
||||
* request_id | "nnn" - a 32bit nonce for this request
|
||||
* alloc_numparam | number of parameters to follow (alloc_param<n>)
|
||||
* alloc_param<n> | one of TYPE (defined below) -- not IDENTIFIER
|
||||
* alloc_return | "SUCCESS"|"IGNORE"
|
||||
* alloc_address | "0x00000000"
|
||||
*
|
||||
* free_numparam | number of parameters to follow (free_param<n>)
|
||||
* free_param<n> | this should be one of TYPE (defined below)
|
||||
* free_return | "SUCCESS"|"IGNORE"
|
||||
* free_address | "0x00000000"
|
||||
*
|
||||
* TYPE ::= "PARTID"|"IDENTIFIER"|"AMOUNT"|"FLOAT"|"DOUBLE"|"NONFLOAT"|
|
||||
* "NONFLOATDOUBLE"
|
||||
*
|
||||
* All requests must specify at least IDENTIFIER and AMOUNT for
|
||||
* alloc, and IDENTIFIER for free.
|
||||
*
|
||||
* Example:
|
||||
* standard malloc, free:
|
||||
*
|
||||
* <Command name="MEM_PATCH_INSTALL">
|
||||
* <Param request_id="4"></Param>
|
||||
* <Param alloc_address="0x120334"></Param>
|
||||
* <Param alloc_numparam="1"></Param>
|
||||
* <Param alloc_param0="AMOUNT"></Param>
|
||||
* <Param alloc_return="IDENTIFIER"></Param>
|
||||
* <Param free_address="0x120354"></Param>
|
||||
* <Param free_numparam="1"></Param>
|
||||
* <Param free_param0="IDENTIFIER"></Param>
|
||||
* <Param free_return="SUCCESS"></Param>
|
||||
* </Command>
|
||||
*
|
||||
*/
|
||||
RTIBool MemLinkPatchCommon(const void * const xmlEngine,
|
||||
MemLinkAllocData * const allocData,
|
||||
MemLinkFreeData * const freeData)
|
||||
{
|
||||
int alloc_params, free_params;
|
||||
|
||||
char *tstring;
|
||||
int i, paramCount;
|
||||
char stringStorage[100];
|
||||
char * stringSignature = (char *)stringStorage;
|
||||
unsigned int tempaddress = 0;
|
||||
|
||||
|
||||
/* Initialize data */
|
||||
allocData->paramNumIdentifier = -1;
|
||||
allocData->paramNumPartId = -1;
|
||||
allocData->paramNumAmount = -1;
|
||||
|
||||
freeData->paramNumIdentifier = -1;
|
||||
freeData->paramNumPartId = -1;
|
||||
|
||||
if ((tstring = parseParamString("alloc_address", xmlEngine)) == NULL) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: No alloc_address tag <aborting>\n");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
/* coverity[secure_coding] */
|
||||
if (sscanf(tstring, "%x", &tempaddress) != 1) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: Bad alloc_address '%s' <aborting>\n",
|
||||
tstring);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
allocData->address =(void*)tempaddress;
|
||||
|
||||
if ((tstring = parseParamString("free_address", xmlEngine)) == NULL) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: No free_address tag <aborting>\n");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
/* coverity[secure_coding] */
|
||||
if (sscanf(tstring, "%x", &tempaddress) != 1) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: Bad free_address '%s' <aborting>\n",
|
||||
tstring);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
freeData->address = (void*)tempaddress;
|
||||
|
||||
if ((tstring = parseParamString("alloc_numparam", xmlEngine)) != NULL) {
|
||||
alloc_params = atoi(tstring);
|
||||
} else {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: Bad alloc parameters address NULL\n");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
if ((tstring = parseParamString("free_numparam", xmlEngine)) != NULL) {
|
||||
free_params = atoi(tstring);
|
||||
} else {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: Bad free parameters address NULL\n");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* Now we can begin examining the values to build the param
|
||||
* signature
|
||||
*/
|
||||
|
||||
stringSignature[0] = 0;
|
||||
for (i = 0, paramCount = 0; i < alloc_params; i++, paramCount++) {
|
||||
char paramName[40];
|
||||
|
||||
snprintf(paramName, sizeof(paramName), "alloc_param%d", i);
|
||||
if ((tstring = parseParamString(paramName, xmlEngine)) == NULL) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: No alloc_param%d tag <aborting>",
|
||||
i);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (strcmp(tstring, TAG_PARTID) == 0) {
|
||||
allocData->paramNumPartId = paramCount;
|
||||
stringSignature = strncat(stringSignature, "I+ ", 3);
|
||||
} else if (strcmp(tstring, TAG_AMOUNT) == 0) {
|
||||
allocData->paramNumAmount = paramCount;
|
||||
stringSignature = strncat(stringSignature, "I+ ", 3);
|
||||
} else if (strcmp(tstring, TAG_FLOAT)) {
|
||||
stringSignature = strncat(stringSignature, "F- ", 3);
|
||||
} else if (strcmp(tstring, TAG_DOUBLE)) {
|
||||
stringSignature = strncat(stringSignature, "D- ", 3);
|
||||
paramCount += 1;
|
||||
} else if (strcmp(tstring, TAG_NONFLOAT)) {
|
||||
stringSignature = strncat(stringSignature, "I- ", 3);
|
||||
} else if (strcmp(tstring, TAG_NONFLOATDOUBLE)) {
|
||||
stringSignature = strncat(stringSignature, "XL- ", 4);
|
||||
paramCount += 1;
|
||||
} else {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: bad parameter %d: %s "
|
||||
"<aborting>\n", i, tstring);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall allocation signature: %s\n",
|
||||
stringSignature);
|
||||
}
|
||||
|
||||
strncpy(allocData->paramString, stringSignature,
|
||||
MEMLINK_PARAM_STRING_LEN - 1);
|
||||
allocData->paramString[MEMLINK_PARAM_STRING_LEN - 1] = 0;
|
||||
|
||||
stringSignature[0] = 0;
|
||||
for (i = 0, paramCount = 0; i < alloc_params; i++, paramCount++) {
|
||||
char paramName[40];
|
||||
snprintf(paramName, sizeof(paramName), "free_param%d", i);
|
||||
if ((tstring = parseParamString(paramName, xmlEngine)) == NULL) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: No free_param%d tag <aborting>",
|
||||
i);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (strcmp(tstring, TAG_PARTID) == 0) {
|
||||
freeData->paramNumPartId = paramCount;
|
||||
stringSignature = strncat(stringSignature, "I+ ", 3);
|
||||
} else if (strcmp(tstring, TAG_ID) == 0) {
|
||||
freeData->paramNumIdentifier = paramCount;
|
||||
stringSignature = strncat(stringSignature, "I+ ", 3);
|
||||
} else if (strcmp(tstring, TAG_FLOAT)) {
|
||||
stringSignature = strncat(stringSignature, "F- ", 3);
|
||||
} else if (strcmp(tstring, TAG_DOUBLE)) {
|
||||
stringSignature = strncat(stringSignature, "D- ", 3);
|
||||
paramCount += 1;
|
||||
} else if (strcmp(tstring, TAG_NONFLOAT)) {
|
||||
stringSignature = strncat(stringSignature, "I- ", 3);
|
||||
} else if (strcmp(tstring, TAG_NONFLOATDOUBLE)) {
|
||||
stringSignature = strncat(stringSignature, "XL- ", 4);
|
||||
paramCount += 1;
|
||||
} else {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: bad parameter %d: %s "
|
||||
"<aborting>\n", i, tstring);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall free signature: %s\n", stringSignature);
|
||||
}
|
||||
|
||||
strncpy(freeData->paramString, stringSignature,
|
||||
MEMLINK_PARAM_STRING_LEN - 1);
|
||||
freeData->paramString[MEMLINK_PARAM_STRING_LEN - 1] = 0;
|
||||
|
||||
/* Find the return values -- alloc return value is forced to be
|
||||
* the identifier at this time */
|
||||
if ((tstring = parseParamString("alloc_return", xmlEngine)) == NULL) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: No alloc_return tag <aborting>");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
if (strcmp(tstring, TAG_ID) == 0) {
|
||||
/* do nothing */
|
||||
} else if (strcmp(tstring, TAG_SUCCESS) == 0) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: Bad alloc_return tag: %s "
|
||||
"<aborting>", tstring);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* We don't currently care about the return value of free -- ignore */
|
||||
|
||||
if (allocData->paramNumAmount == -1) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: no alloc `amount' indicator "
|
||||
"<aborting>\n");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
if (freeData->paramNumIdentifier == -1) {
|
||||
if (MEMSCOPE_DEBUG_MEMLINK) {
|
||||
printf("MemLinkPatchInstall: no free `identifier' indicator "
|
||||
"<aborting>\n");
|
||||
}
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
/**
|
||||
* Informs the host about the status of an attempt to patch
|
||||
*/
|
||||
void MemLinkRequestStatusSend(Link *link, unsigned int address, RTIBool status)
|
||||
{
|
||||
char buf[128];
|
||||
const int size = snprintf(buf, sizeof(buf),
|
||||
"<request-status id=\"%x\" status=\"%s\">"
|
||||
"</request-status>",
|
||||
address, ((status == RTI_TRUE ) ? "ok" : "error"));
|
||||
|
||||
LinkDataSend(link, buf, size);
|
||||
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
/**
|
||||
* Informs the host of target-side heap corruption
|
||||
*/
|
||||
void MemLinkHeapCorruptSend(Link *link, int status, void *block)
|
||||
{
|
||||
char buf[128];
|
||||
const int size = snprintf(buf, sizeof(buf),
|
||||
"<corruption id=\"%x\" block=\"%p\">"
|
||||
"</corruption>",
|
||||
status, block);
|
||||
|
||||
LinkDataSend(link, buf, size);
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void LinkPingRespond(Link *link)
|
||||
{
|
||||
LinkDataSend(link, "<ping></ping>", 13);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01c,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
# 01b,03jun10,jpb Added _WRS_CONFIG_RTP conditionals.
|
||||
# 01a,26mar06,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../..
|
||||
|
||||
vpath %.c $(TOOLS_SRC_ROOT)/memscope/comm
|
||||
LIB_BASE_NAME = memscope
|
||||
|
||||
# Including defs.library to see if _WRS_CONFIG_xxx is defined.
|
||||
# It must be after LIB_BASE_NAME
|
||||
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
EXTRA_DEFINE += -DMEMSCOPEVERSION=\"3.7a\"
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/rtilib/include/vx \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include/vx \
|
||||
-I$(COMP_STACKTRACE_PATH)/include \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= memlink.o memscope.o memscope_old.o wtxcalls.o memlinkcomm.o
|
||||
|
||||
ifdef _WRS_CONFIG_RTP
|
||||
OBJS += rtp_support.o
|
||||
endif
|
||||
|
||||
PKG_H= memscope.pkg.h memscope_old.pkg.h wtxcalls.pkg.h rtp_support.pkg.h \
|
||||
memlinkcomm.pkg.h memlink.pkg.h
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
|
||||
# end of memscope/target
|
||||
@@ -0,0 +1,628 @@
|
||||
/* memlink.c - target side tcp link code for MemScope. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, 2007-2010, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,12oct13,wzc Fix prevent warnings.
|
||||
01c,16dec10,zlo Use new typed error value(WIND00246074).
|
||||
01b,28sep10,jpb Added memLib.h for memSysPartId.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
3.4a,27aug08,mas added vsbConfig.h; changed _WRS_XV_SMP to _WRS_CONFIG_SMP
|
||||
3.3a,29jan07,mas made SMP-compliant
|
||||
3.0a,01mar02,pac Added heap check install, malloc/free install
|
||||
1.0, 31jan02,pca Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Target side tcp link code for MemScope.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <usrConfig.h> /* for sysPhysMemTop */
|
||||
#include <memLib.h> /* memSysPartId */
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
#include <eventsxml.h>
|
||||
#include "memscope.pkg.h"
|
||||
|
||||
#pragma begin_Package
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "memlinkcomm.pkg.h"
|
||||
#pragma end_Package
|
||||
|
||||
#if !VXWORKS_VERSION_6_0_OR_BETTER
|
||||
# include <rtitools/heapCheck.h>
|
||||
#endif
|
||||
|
||||
/* defines */
|
||||
|
||||
// TD: Describe all defines
|
||||
#define MEMSCOPE_DEBUG_MEMLINK (0)
|
||||
|
||||
#if MEMSCOPE_DEBUG_MEMLINK
|
||||
# define dprintf logMsg
|
||||
#else
|
||||
# define dprintf(fmt,args...)
|
||||
#endif
|
||||
|
||||
#define MEMSCOPE_MAX_BLOCKS (20) /* for HeapGetPoolBlocks */
|
||||
|
||||
#define LINK_STACK_SIZE (12 * 1024)
|
||||
|
||||
#define TASK_NAME ("MemLink")
|
||||
|
||||
private struct {
|
||||
Link link;
|
||||
MemScopeData *memscope;
|
||||
unsigned int reportedOverflows;
|
||||
} MemLink;
|
||||
|
||||
Private void MemLinkShutdown(const void * const xmlEngine);
|
||||
Private void MemLinkMemPartOptionsSet(const void * const xmlEngine);
|
||||
Private void MemLinkFreeTaggingTrue(const void * const xmlEngine);
|
||||
Private void MemLinkFreeTaggingFalse(const void * const xmlEngine);
|
||||
Private void MemLinkPatchInstall(const void * const xmlEngine);
|
||||
Private void MemLinkPatchRemove(const void * const xmlEngine);
|
||||
Private void MemLinkHeapSend(const void * const xmlEngine);
|
||||
Private void MemLinkPingResponse(const void * const xmlEngine);
|
||||
#if !VXWORKS_VERSION_6_0_OR_BETTER
|
||||
Private void MemLinkHeapCheckRemove(const void * const xmlEngine);
|
||||
Private void MemLinkHeapCheckInstall(const void * const xmlEngine);
|
||||
#endif
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Fire up the link.
|
||||
*/
|
||||
RTIBool MemLinkStart(MemScopeData * const memscope,
|
||||
const unsigned int pollDelay,
|
||||
int linkPriority, int tcpPortNumber)
|
||||
{
|
||||
dprintf("Starting MemLink\n");
|
||||
|
||||
if (LinkCreate(&MemLink.link, tcpPortNumber, pollDelay) != RTI_TRUE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
dprintf("Registering MemLink callbacks\n");
|
||||
|
||||
/* Register commands we can handle: MAKE SURE THAT MEMLINK_MAX_CALLBACKS
|
||||
* in memlinkcomm.c is set to be a high enough number!
|
||||
*/
|
||||
|
||||
registerFunction(SHUTDOWN, MemLinkShutdown,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(TAG_FREE_TRUE, MemLinkFreeTaggingTrue,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(TAG_FREE_FALSE, MemLinkFreeTaggingFalse,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(MEMPART_OPTIONS_SET, MemLinkMemPartOptionsSet,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
#if !VXWORKS_VERSION_6_0_OR_BETTER
|
||||
/* Functions for checking the heap before / after arbitrary
|
||||
* functions
|
||||
*/
|
||||
registerFunction(HEAP_CHECK_INSTALL, MemLinkHeapCheckInstall,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(HEAP_CHECK_REMOVE, MemLinkHeapCheckRemove,
|
||||
0, MemLink.link.xmlEngine);
|
||||
#endif /* #if !VXWORKS_VERSION_6_0_OR_BETTER */
|
||||
|
||||
/* Functions for arbitrary patching of allocation/deallocation
|
||||
* functions
|
||||
*/
|
||||
registerFunction(MEM_PATCH_INSTALL, MemLinkPatchInstall,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(MEM_PATCH_REMOVE, MemLinkPatchRemove,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
/* Functions for sending the heap if requested */
|
||||
registerFunction(MEM_HEAP_SEND, MemLinkHeapSend,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
/* Functions for starting / stopping collection */
|
||||
registerFunction(MEM_COLLECTION_ENABLE, MemScopeCollectionEnable,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(MEM_COLLECTION_DISABLE, MemScopeCollectionDisable,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
registerFunction(PING, MemLinkPingResponse,
|
||||
0, MemLink.link.xmlEngine);
|
||||
|
||||
MemLink.memscope = memscope;
|
||||
MemLink.reportedOverflows = 0;
|
||||
|
||||
/* Start the link task if one doesn't exist */
|
||||
if (taskNameToId(TASK_NAME) == ERROR){
|
||||
|
||||
if (linkPriority < 0) {
|
||||
linkPriority = 0;
|
||||
} else if (linkPriority > 255) {
|
||||
linkPriority = 255;
|
||||
}
|
||||
|
||||
dprintf("Spawning MemLink engine\n");
|
||||
|
||||
if (taskSpawn(TASK_NAME, linkPriority, VX_FP_TASK,
|
||||
LINK_STACK_SIZE,
|
||||
(FUNCPTR)MemLinkEngine,
|
||||
(int) &MemLink.link,
|
||||
0,0,0,0,0,0,0,0,0) == TASK_ID_ERROR)
|
||||
{
|
||||
MemLink.link.shouldExit = RTI_TRUE;
|
||||
return RTI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void MemLinkPingResponse(const void * const xmlEngine)
|
||||
{
|
||||
LinkPingRespond(&MemLink.link);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void MemLinkShutdown(const void * const xmlEngine)
|
||||
{
|
||||
dprintf("Shutdown!\n");
|
||||
|
||||
MemLink.link.shouldExit = RTI_TRUE;
|
||||
MemScopeTargetExit();
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void MemLinkFreeTaggingTrue(const void * const xmlEngine)
|
||||
{
|
||||
MemLink.memscope->freeTagging = RTI_TRUE;
|
||||
dprintf("Start tagging.\n");
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void MemLinkFreeTaggingFalse(const void * const xmlEngine)
|
||||
{
|
||||
MemLink.memscope->freeTagging = RTI_FALSE;
|
||||
dprintf("Stop tagging.\n");
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void MemLinkMemPartOptionsSet(const void * const xmlEngine)
|
||||
{
|
||||
const PART_ID partitionId = //(PART_ID) atoi(partString);
|
||||
(PART_ID) atoi(parseParamString("partitionId",xmlEngine));
|
||||
|
||||
const char * allocLog = parseParamString("allocLog",xmlEngine);
|
||||
const char * freeLog = parseParamString("freeLog",xmlEngine);
|
||||
const char * allocSuspend = parseParamString("allocSuspend",xmlEngine);
|
||||
const char * freeSuspend = parseParamString("freeSuspend",xmlEngine);
|
||||
/* const char * checkBlocks = parseParamString("checkBlocks",xmlEngine); */
|
||||
|
||||
unsigned int options = 0;
|
||||
if ((allocLog != NULL) && strcmp(allocLog, "true") == 0) {
|
||||
options |= MEM_ALLOC_ERROR_LOG_FLAG;
|
||||
}
|
||||
|
||||
if ((freeLog != NULL) && strcmp(freeLog, "true") == 0) {
|
||||
options |= MEM_BLOCK_ERROR_LOG_FLAG;
|
||||
}
|
||||
|
||||
if ((allocSuspend != NULL) && strcmp(allocSuspend, "true") == 0) {
|
||||
options |= MEM_ALLOC_ERROR_SUSPEND_FLAG;
|
||||
}
|
||||
|
||||
if ((freeSuspend != NULL) && strcmp(freeSuspend, "true") == 0) {
|
||||
options |= MEM_BLOCK_ERROR_SUSPEND_FLAG;
|
||||
}
|
||||
/*
|
||||
if ( strcmp(checkBlocks, "true") == 0) {
|
||||
options |= MEM_BLOCK_ERROR_SUSPEND_FLAG;
|
||||
}
|
||||
*/
|
||||
dprintf("memPartOptionsSet...\t%p\n", (void *)partitionId);
|
||||
dprintf("\t%s\n", allocLog);
|
||||
dprintf("\t%s\n", freeLog);
|
||||
dprintf("\t%s\n", allocSuspend);
|
||||
dprintf("\t%s\n", freeSuspend);
|
||||
dprintf("\t0x%08x\n", options);
|
||||
|
||||
if ( memPartOptionsSet(partitionId, options) != OK) {
|
||||
logMsg("memPartOptionsSet failed:\t%p\t0x%08x\n",
|
||||
partitionId, options);
|
||||
}
|
||||
}
|
||||
|
||||
#if !VXWORKS_VERSION_6_0_OR_BETTER
|
||||
Private
|
||||
void MemLinkHeapCheckInstall(const void * const xmlEngine)
|
||||
{
|
||||
void *beforeFunction = NULL;
|
||||
void *afterFunction = NULL;
|
||||
|
||||
unsigned int request_id;
|
||||
unsigned int address;
|
||||
const char *type = parseParamString("type", (void *)xmlEngine);
|
||||
const char *temp = parseParamString("functionAddress", (void *)xmlEngine);
|
||||
|
||||
request_id = atoi(parseParamString("request_id", (void *)xmlEngine));
|
||||
|
||||
if (sscanf(temp, "0x%x", &address) != 1) {
|
||||
dprintf("MemLinkHeapCheckInstall: could not decipher address!\n");
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Find out whether we patch before and after or just one */
|
||||
if ( type == NULL ) {
|
||||
dprintf("MemLinkHeapCheckInstall: blank type parameter!\n");
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("MemLinkHeapCheckInstall: 0x%08x / %s\n", address, type);
|
||||
|
||||
if ( strcmp(type, "before") == 0) {
|
||||
beforeFunction = (void *)MemScopeHeapCheck;
|
||||
/* not available currently
|
||||
} else if ( strcmp(type, "after") == 0) {
|
||||
afterFunction = (void *)MemLinkHeapCheck;
|
||||
*/
|
||||
} else /* ( strcmp(type, "both") == 0 ) */ {
|
||||
beforeFunction = (void *)MemScopeHeapCheck;
|
||||
afterFunction = (void *)MemScopeHeapCheck;
|
||||
}
|
||||
|
||||
#if !VXWORKS_VERSION_6_0_OR_BETTER
|
||||
HeapToolsInit();
|
||||
#endif
|
||||
|
||||
if (RtiTools_PatchFunctionSet((void *)address, beforeFunction, 0,
|
||||
afterFunction, 0, 0) != RTI_TRUE) {
|
||||
dprintf("MemLinkHeapCheckInstall could not patch @ 0x%x\n",
|
||||
address);
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Set behavior to suspend if not a critical task on patch failure */
|
||||
RtiTools_PatchStopOptionSet(0, RTI_TRUE);
|
||||
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void MemLinkHeapCheckRemove(const void * const xmlEngine)
|
||||
{
|
||||
unsigned int request_id;
|
||||
const char *temp = parseParamString("functionAddress", (void *)xmlEngine);
|
||||
unsigned int address;
|
||||
|
||||
request_id = atoi(parseParamString("request_id", (void *)xmlEngine));
|
||||
|
||||
if (sscanf(temp, "0x%x", &address) != 1) {
|
||||
dprintf("MemLinkHeapCheckInstall: could not decipher address!\n");
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf("MemLinkHeapCheckRemove: 0x%08x\n", address);
|
||||
|
||||
if (RtiTools_PatchUnset((void *)address, RTI_TRUE) != RTI_TRUE) {
|
||||
dprintf("MemLinkHeapCheckRemove failed @ 0x%08x\n", address);
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
}
|
||||
#endif /* #if !VXWORKS_VERSION_6_0_OR_BETTER */
|
||||
|
||||
|
||||
Private
|
||||
/*
|
||||
* Expects the same format found in MemLinkPatchCommon to be
|
||||
* in the data.
|
||||
*
|
||||
*/
|
||||
void MemLinkPatchInstall(const void * const xmlEngine)
|
||||
{
|
||||
const unsigned int request_id =
|
||||
atoi(parseParamString("request_id", xmlEngine));
|
||||
|
||||
#if MEMSCOPE_NO_PATCHING
|
||||
dprintf("Patching target with heap patch method [tcp mode]\n");
|
||||
MemScopeOldStart();
|
||||
#else
|
||||
MemLinkAllocData linkAllocData;
|
||||
MemLinkFreeData linkFreeData;
|
||||
MemScopeAllocData scopeAllocData;
|
||||
MemScopeFreeData scopeFreeData;
|
||||
|
||||
/* Check for appropriate variables */
|
||||
if (MemLinkPatchCommon(xmlEngine, &linkAllocData, &linkFreeData)
|
||||
== RTI_FALSE)
|
||||
{
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
scopeAllocData.address = linkAllocData.address;
|
||||
scopeAllocData.paramNumPartId = linkAllocData.paramNumPartId;
|
||||
scopeAllocData.paramNumIdentifier = linkAllocData.paramNumIdentifier;
|
||||
scopeAllocData.paramNumAmount = linkAllocData.paramNumAmount;
|
||||
|
||||
scopeFreeData.address = linkFreeData.address;
|
||||
scopeFreeData.paramNumPartId = linkFreeData.paramNumPartId;
|
||||
scopeFreeData.paramNumIdentifier = linkFreeData.paramNumIdentifier;
|
||||
|
||||
dprintf("Creating patch signatures\n");
|
||||
|
||||
if (RtiTools_ParamSignatureCreate(linkAllocData.paramString,
|
||||
&scopeAllocData.signature) == RTI_FALSE)
|
||||
{
|
||||
dprintf("Could not create signature from '%s'\n", linkAllocData.paramString);
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
}
|
||||
if (RtiTools_ParamSignatureCreate(linkFreeData.paramString,
|
||||
&scopeFreeData.signature) == RTI_FALSE)
|
||||
{
|
||||
dprintf("Could not create signature from '%s'\n", linkFreeData.paramString);
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
}
|
||||
|
||||
dprintf("Patching target [tcp mode]\n");
|
||||
|
||||
/* Should be done -- now make the patch */
|
||||
if (MemScopePartStart(&scopeAllocData, &scopeFreeData) == RTI_FALSE) {
|
||||
dprintf("MemLinkPatchInstall: MemScopePartStart failed!\n");
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_FALSE);
|
||||
return;
|
||||
}
|
||||
#endif /* if MEMSCOPE_NO_PATCHING */
|
||||
|
||||
MemLinkRequestStatusSend(&MemLink.link, request_id, RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/*
|
||||
* Removes the current malloc/free patches
|
||||
*/
|
||||
void MemLinkPatchRemove(const void * const xmlEngine)
|
||||
{
|
||||
MemScopePartFinish();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Informs the host of the status of the system partition before
|
||||
* MemScope was paying attention.
|
||||
**/
|
||||
void MemLinkHeapSend(const void * const xmlEngine)
|
||||
{
|
||||
#if 0
|
||||
int i, j;
|
||||
int poolCount; /* Number of pools */
|
||||
int blockCount; /* Number of blocks actually retrieved */
|
||||
int curBlockCount; /* Number of blocks retrieved so far */
|
||||
|
||||
HeapPoolEntry *pools; /* Storage for pools */
|
||||
HeapBlockEntry blocks[MEMSCOPE_MAX_BLOCKS]; /* Storage for blocks */
|
||||
char buf[80]; /* <block start="0x%08x" length="0x%08x" /> */
|
||||
|
||||
/* First, find all the pools */
|
||||
dprintf("Discovering preallocated memory\n");
|
||||
|
||||
/* Some targets can't.. */
|
||||
if (HeapFindPoolsCapable() == RTI_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
taskLock();
|
||||
|
||||
HeapFindPools(0, 0);
|
||||
poolCount = HeapCountPools();
|
||||
pools = HeapGetPools();
|
||||
|
||||
|
||||
/* For each pool, find the list of used blocks and send them to the link */
|
||||
for (i = 0; i < poolCount; i++) {
|
||||
|
||||
dprintf("Found pool @ %x\n",
|
||||
(unsigned int)pools[i].poolTop);
|
||||
|
||||
blockCount = 0;
|
||||
curBlockCount = 0;
|
||||
|
||||
do {
|
||||
blockCount = HeapGetPoolBlocks(blocks, pools[i].poolTop,
|
||||
curBlockCount, MEMSCOPE_MAX_BLOCKS,
|
||||
RTI_TRUE);
|
||||
|
||||
for (j = 0; j < blockCount; j++) {
|
||||
|
||||
sprintf(buf,
|
||||
"<used-block start=\"0x%08x\" "
|
||||
"length=\"0x%08x\" ></used-block>",
|
||||
(unsigned int)blocks[j].blockStart,
|
||||
(unsigned int)blocks[j].blockSize);
|
||||
|
||||
LinkDataSend(&MemLink.link, buf, strlen(buf));
|
||||
|
||||
dprintf("sent %s\n", buf);
|
||||
}
|
||||
curBlockCount += blockCount;
|
||||
}
|
||||
while (blockCount == MEMSCOPE_MAX_BLOCKS);
|
||||
|
||||
} /* for each pool */
|
||||
|
||||
taskUnlock();
|
||||
free(pools);
|
||||
|
||||
dprintf("Completed discovery of preallocated memory\n");
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
* Link engine callbacks
|
||||
*/
|
||||
|
||||
Package
|
||||
/**
|
||||
* Send data needed once per link creation.
|
||||
*/
|
||||
RTIBool MemLinkSendInitialData(Link * const link)
|
||||
{
|
||||
return MemLinkVersionSend((unsigned int) memSysPartId,
|
||||
(unsigned int) sysPhysMemTop(),
|
||||
#ifdef SMP_CONFIG
|
||||
(unsigned int) kernelIdGet(),
|
||||
#else
|
||||
(unsigned int) kernelId,
|
||||
#endif
|
||||
MemScopePatchCapableGet(),
|
||||
RTI_FALSE,
|
||||
link);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Empty the message Q of records and send them up the link.
|
||||
*/
|
||||
RTIBool MemLinkRecordsSend(Link * const link)
|
||||
{
|
||||
const int dataRecords = msgQNumMsgs(MemLink.memscope->msgQId);
|
||||
int i;
|
||||
|
||||
if (dataRecords == ERROR){
|
||||
logMsg("Error getting memscope data.\n");
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < dataRecords; ++i) {
|
||||
char BUFFER_ALIGN dataBuff[MAX_MEMSCOPE_MSG_LEN];
|
||||
unsigned int code;
|
||||
const int msgLength =
|
||||
msgQReceive(MemLink.memscope->msgQId, dataBuff,
|
||||
MemLink.memscope->msgLen,WAIT_FOREVER);
|
||||
|
||||
if (msgLength == ERROR) {
|
||||
logMsg("Error receiving records.\n");
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
code = *((unsigned int*)dataBuff);
|
||||
switch(code) {
|
||||
case MEMSCOPE_ALLOC:
|
||||
{
|
||||
if (MemLinkAllocSend((unsigned int *)(dataBuff + sizeof(unsigned int)),
|
||||
taskName(((unsigned int *)dataBuff)[4]),
|
||||
MemLink.memscope->stackDepth,
|
||||
link) != RTI_TRUE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MEMSCOPE_FREE:
|
||||
{
|
||||
if (MemLinkFreeSend((unsigned int *)(dataBuff + sizeof(unsigned int)),
|
||||
taskName(((unsigned int *)dataBuff)[4]),
|
||||
MemLink.memscope->stackDepth,
|
||||
link) != RTI_TRUE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MEMSCOPE_CORRELATE:
|
||||
{
|
||||
if (MemLinkCorrelateSend(link) != RTI_TRUE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MEMSCOPE_HEAP_CORRUPTION:
|
||||
{
|
||||
MemLinkHeapCorruptSend(link,
|
||||
*(unsigned int *)(dataBuff + sizeof(unsigned int)),
|
||||
*(void **)(dataBuff + 8));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
logMsg("Unknown msg type, %i.\n", code);
|
||||
} /* switch (code) */
|
||||
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Check to see if we've overflowed our msgQ since last time
|
||||
* we checked. If so, notify the gui.
|
||||
*/
|
||||
RTIBool MemLinkCheckOverflows(Link * const link)
|
||||
{
|
||||
|
||||
const unsigned int overflows = MemLink.memscope->timesQFull;
|
||||
|
||||
if (overflows > MemLink.reportedOverflows) {
|
||||
const RTIBool status = MemLinkOverflowsSend(overflows, link);
|
||||
MemLink.reportedOverflows = overflows;
|
||||
return status;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/* memlink.pkg.h - built from: memlink.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef memlink_pkg_h
|
||||
#define memlink_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "memlinkcomm.pkg.h"
|
||||
|
||||
|
||||
/**
|
||||
* Fire up the link.
|
||||
*/
|
||||
extern RTIBool MemLinkStart(MemScopeData * const memscope,
|
||||
const unsigned int pollDelay,
|
||||
int linkPriority, int tcpPortNumber);
|
||||
|
||||
|
||||
/**
|
||||
* Send data needed once per link creation.
|
||||
*/
|
||||
extern RTIBool MemLinkSendInitialData(Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Empty the message Q of records and send them up the link.
|
||||
*/
|
||||
extern RTIBool MemLinkRecordsSend(Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if we've overflowed our msgQ since last time
|
||||
* we checked. If so, notify the gui.
|
||||
*/
|
||||
extern RTIBool MemLinkCheckOverflows(Link * const link);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* memlink_pkg_h */
|
||||
@@ -0,0 +1,221 @@
|
||||
/* memlinkcomm.pkg.h - built from: ../../memscope/comm/memlinkcomm.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef memlinkcomm_pkg_h
|
||||
#define memlinkcomm_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <rtilib/rti_tcp.h>
|
||||
#include <rtilib/rti_osapi.h>
|
||||
|
||||
|
||||
#define MEMLINK_PARAM_STRING_LEN (32) /* max parameter creation string length */
|
||||
|
||||
|
||||
#define MAX_COMMAND_LENGTH (1024)
|
||||
|
||||
|
||||
/***************************************
|
||||
* Commands
|
||||
*/
|
||||
#define SHUTDOWN ("Shutdown")
|
||||
#define TAG_FREE_TRUE ("FREE_TAGGING_TRUE")
|
||||
#define TAG_FREE_FALSE ("FREE_TAGGING_FALSE")
|
||||
#define MEMPART_OPTIONS_SET ("MEMPART_SET_OPTIONS")
|
||||
#define HEAP_CHECK_INSTALL ("HEAP_CHECK_INSTALL")
|
||||
#define HEAP_CHECK_REMOVE ("HEAP_CHECK_REMOVE")
|
||||
#define MEM_PATCH_INSTALL ("MEM_PATCH_INSTALL")
|
||||
#define MEM_PATCH_REMOVE ("MEM_PATCH_REMOVE")
|
||||
#define MEM_HEAP_SEND ("MEM_HEAP_SEND")
|
||||
#define MEM_COLLECTION_ENABLE ("MEM_COLLECTION_ENABLE")
|
||||
#define MEM_COLLECTION_DISABLE ("MEM_COLLECTION_DISABLE")
|
||||
#define PING ("ping")
|
||||
|
||||
|
||||
typedef enum {
|
||||
RUNNING,
|
||||
DONE
|
||||
} ThreadStatus;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void * xmlEngine;
|
||||
RTITcp* tcpLink;
|
||||
char cmdBuff[MAX_COMMAND_LENGTH];
|
||||
unsigned int cmdStartPosition;
|
||||
RTIBool shouldExit;
|
||||
ThreadStatus status;
|
||||
RTINtpTime pollDelay;
|
||||
} Link;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
int paramNumPartId;
|
||||
int paramNumIdentifier;
|
||||
int paramNumAmount;
|
||||
char paramString[MEMLINK_PARAM_STRING_LEN];
|
||||
} MemLinkAllocData;
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
int paramNumPartId;
|
||||
int paramNumIdentifier;
|
||||
char paramString[MEMLINK_PARAM_STRING_LEN];
|
||||
} MemLinkFreeData;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Debugging call which dumps everything we know
|
||||
* about the Link object.
|
||||
**/
|
||||
extern void dumpLink(const Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Create a link object.
|
||||
* This will open a socket for listening and warm up the XML
|
||||
* parser.
|
||||
*/
|
||||
extern RTIBool LinkCreate(Link * const link, const unsigned int port,
|
||||
const unsigned int delay);
|
||||
|
||||
|
||||
extern RTIBool LinkDataSend( const Link * const link, const char * data,
|
||||
unsigned int size);
|
||||
|
||||
|
||||
/**
|
||||
* Inform the host of the target version.
|
||||
**/
|
||||
extern RTIBool MemLinkVersionSend(const unsigned int systemPartition,
|
||||
const unsigned int memoryTop,
|
||||
const unsigned int kernelPdId,
|
||||
const RTIBool patchCapable,
|
||||
const RTIBool poolFindCapable,
|
||||
const Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Sends a record of a pre-allocated heap block
|
||||
**/
|
||||
extern void MemLinkHeapBlockSend(const unsigned int blockStart,
|
||||
const unsigned int size,
|
||||
const Link * const link);
|
||||
|
||||
|
||||
extern RTIBool MemLinkAllocSend(const unsigned int data[],
|
||||
const char * const taskName,
|
||||
const unsigned int stackDepth,
|
||||
const Link * const link);
|
||||
|
||||
|
||||
extern RTIBool MemLinkFreeSend(const unsigned int data[],
|
||||
const char * const taskName,
|
||||
const unsigned int stackDepth,
|
||||
const Link * const link);
|
||||
|
||||
|
||||
extern RTIBool MemLinkCorrelateSend(const Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Send the number of target overflows to the host.
|
||||
*/
|
||||
extern RTIBool MemLinkOverflowsSend(const unsigned int overflows,
|
||||
const Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* State machine responsible for maintaining the memlink;
|
||||
* sending data and processing commands
|
||||
*/
|
||||
extern void MemLinkEngine(Link * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Common patch code - to be called from link-specific patch
|
||||
* code to cope with the results.
|
||||
*
|
||||
* Requires the following parameters:
|
||||
* xmlEngine --
|
||||
* MemScopeAllocData - to be populated and returned
|
||||
* MemScopeFreeData - to be populated and returned
|
||||
*
|
||||
* Returns: RTI_TRUE upon success, RTI_FALSE upon failure. In either
|
||||
* case, values stored in allocData and freeData have been altered.
|
||||
*
|
||||
*
|
||||
* Installs the requested functions as malloc/free replacements
|
||||
* Expects the following parameters:
|
||||
* request_id | "nnn" - a 32bit nonce for this request
|
||||
* alloc_numparam | number of parameters to follow (alloc_param<n>)
|
||||
* alloc_param<n> | one of TYPE (defined below) -- not IDENTIFIER
|
||||
* alloc_return | "SUCCESS"|"IGNORE"
|
||||
* alloc_address | "0x00000000"
|
||||
*
|
||||
* free_numparam | number of parameters to follow (free_param<n>)
|
||||
* free_param<n> | this should be one of TYPE (defined below)
|
||||
* free_return | "SUCCESS"|"IGNORE"
|
||||
* free_address | "0x00000000"
|
||||
*
|
||||
* TYPE ::= "PARTID"|"IDENTIFIER"|"AMOUNT"|"FLOAT"|"DOUBLE"|"NONFLOAT"|
|
||||
* "NONFLOATDOUBLE"
|
||||
*
|
||||
* All requests must specify at least IDENTIFIER and AMOUNT for
|
||||
* alloc, and IDENTIFIER for free.
|
||||
*
|
||||
* Example:
|
||||
* standard malloc, free:
|
||||
*
|
||||
* <Command name="MEM_PATCH_INSTALL">
|
||||
* <Param request_id="4"></Param>
|
||||
* <Param alloc_address="0x120334"></Param>
|
||||
* <Param alloc_numparam="1"></Param>
|
||||
* <Param alloc_param0="AMOUNT"></Param>
|
||||
* <Param alloc_return="IDENTIFIER"></Param>
|
||||
* <Param free_address="0x120354"></Param>
|
||||
* <Param free_numparam="1"></Param>
|
||||
* <Param free_param0="IDENTIFIER"></Param>
|
||||
* <Param free_return="SUCCESS"></Param>
|
||||
* </Command>
|
||||
*
|
||||
*/
|
||||
extern RTIBool MemLinkPatchCommon(const void * const xmlEngine,
|
||||
MemLinkAllocData * const allocData,
|
||||
MemLinkFreeData * const freeData);
|
||||
|
||||
|
||||
/**
|
||||
* Informs the host about the status of an attempt to patch
|
||||
*/
|
||||
extern void MemLinkRequestStatusSend(Link *link, unsigned int address, RTIBool status);
|
||||
|
||||
|
||||
/**
|
||||
* Informs the host of target-side heap corruption
|
||||
*/
|
||||
extern void MemLinkHeapCorruptSend(Link *link, int status, void *block);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern void LinkPingRespond(Link *link);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* memlinkcomm_pkg_h */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,344 @@
|
||||
/* memscope.pkg.h - built from: memscope.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef memscope_pkg_h
|
||||
#define memscope_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <rtilib/vxVersions.h>
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# include <vxAtomicLib.h>
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# include <vxAtomicLib.h>
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <msgQLib.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/fastBuffer.h>
|
||||
#include <rtilib/stSpinLock.h>
|
||||
#include "memscope_old.pkg.h" /* for MEMSCOPE_NO_PATCHING definition */
|
||||
|
||||
#if !MEMSCOPE_NO_PATCHING
|
||||
# include <rtitools/rtitools_param.h>
|
||||
# include <rtitools/patch.h>
|
||||
#endif
|
||||
#include <rtitools/rtitools_filter.h>
|
||||
|
||||
|
||||
|
||||
#include <rtilib/vxVersions.h>
|
||||
#define MAX_STACKDEPTH (64)
|
||||
|
||||
/* note that we need the host clause here as well since the generated
|
||||
header file is used for both host and target codebases */
|
||||
|
||||
/* MEMSCOPE_HEADER_SIZE = code + partId + addr + nBytes + tid + pid + group */
|
||||
#define MEMSCOPE_HEADER_SIZE (sizeof(int) + sizeof(void *) + sizeof(void *) \
|
||||
+ sizeof(unsigned int) + sizeof(void *) \
|
||||
+ sizeof(void *) + sizeof(unsigned int))
|
||||
|
||||
#define MAX_MEMSCOPE_MSG_LEN (MEMSCOPE_HEADER_SIZE + sizeof(void*) * MAX_STACKDEPTH)
|
||||
|
||||
#define MEMSCOPE_ALLOC (10)
|
||||
#define MEMSCOPE_FREE (11)
|
||||
#define MEMSCOPE_CORRELATE (13)
|
||||
#define MEMSCOPE_HEAP_CORRUPTION (14)
|
||||
|
||||
|
||||
/* WindView events */
|
||||
#define EVENT_MEM_START (39200)
|
||||
#define EVENT_MEM_STOP (39201)
|
||||
#define EVENT_MEM_ALLOC (39202)
|
||||
#define EVENT_MEM_FREE (39203)
|
||||
#define EVENT_MEM_FAILEDALLOC (39204)
|
||||
#define EVENT_MEM_OVERFLOW (39205)
|
||||
|
||||
|
||||
|
||||
/* Vx 6.4 changed the type names of these structures */
|
||||
#if !VXWORKS_VERSION_6_4_OR_BETTER
|
||||
typedef DL_NODE _Vx_DL_NODE;
|
||||
typedef DL_LIST _Vx_DL_LIST;
|
||||
#endif
|
||||
|
||||
/* We need both the target and host define checks since this
|
||||
is placed into an external header file used by both
|
||||
the target code and the host code. */
|
||||
#define ENDOFSTACK ((void *) -1)
|
||||
#define MAX_IGNORE_TASKS 8
|
||||
|
||||
#define v0printf logMsg
|
||||
#define v1printf if (MemScope.verbosity >= 1) v0printf
|
||||
#define v2printf if (MemScope.verbosity >= 2) v0printf
|
||||
#define v3printf if (MemScope.verbosity >= 3) v0printf
|
||||
|
||||
|
||||
|
||||
#if !MEMSCOPE_NO_PATCHING
|
||||
typedef struct {
|
||||
void *address;
|
||||
int paramNumPartId;
|
||||
int paramNumIdentifier;
|
||||
int paramNumAmount;
|
||||
RtiTools_ParamSignature signature;
|
||||
} MemScopeAllocData;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
int paramNumPartId;
|
||||
int paramNumIdentifier;
|
||||
RtiTools_ParamSignature signature;
|
||||
} MemScopeFreeData;
|
||||
#endif /* if !MEMSCOPE_NO_PATCHING */
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int msgLen;
|
||||
RtiTools_Filter *filter;
|
||||
unsigned int timesQFull;
|
||||
unsigned int stackDepth;
|
||||
MSG_Q_ID msgQId;
|
||||
RTIBool msgQFull;
|
||||
unsigned int verbosity;
|
||||
RTIBool freeTagging;
|
||||
RTIBool collectionEnabled;
|
||||
RTIBool wvEnable;
|
||||
RTIBool triggerEnable;
|
||||
RTIBool rtvEnable;
|
||||
char *wtxRecvBuff;
|
||||
#if !MEMSCOPE_NO_PATCHING
|
||||
FastBufferID regsetBufferPool;
|
||||
RtiTools_ParamSignature reallocSignature;
|
||||
MemScopeAllocData allocData;
|
||||
MemScopeFreeData freeData;
|
||||
void *qFreeDataAddress;
|
||||
RtiTools_ParamSignature qFreeDataSignature;
|
||||
FastBufferID nestCheckBufferPool;
|
||||
_Vx_DL_LIST nestCheckList; /* access must be protected with a lock */
|
||||
#endif /* if !MEMSCOPE_NO_PATCHING */
|
||||
#ifdef SMP_CONFIG
|
||||
st_rwLock nestLock;
|
||||
#endif
|
||||
} MemScopeData;
|
||||
|
||||
|
||||
extern unsigned int MEMSCOPE_LIB_VERSION;
|
||||
|
||||
extern MemScopeData MemScope;
|
||||
|
||||
|
||||
#if !MEMSCOPE_NO_PATCHING
|
||||
|
||||
extern int MemScopeAllocBeforeRoutine(PatchInstance *patch,
|
||||
REG_SET *regs, long userData[8]);
|
||||
|
||||
extern int MemScopeFreeBeforeRoutine(PatchInstance *patch,
|
||||
REG_SET *regs, long userData[8]);
|
||||
|
||||
extern int MemScopeQFreeBeforeRoutine(PatchInstance *patch,
|
||||
REG_SET *regs, long userData[8]);
|
||||
|
||||
extern int MemScopeAllocAfterRoutine(PatchInstance *patch, long userData[8],
|
||||
void * returnValue);
|
||||
|
||||
extern int MemScopeQFreeAfterRoutine(PatchInstance *patch, long userData[8],
|
||||
void * returnValue);
|
||||
|
||||
extern int MemScopeReallocBeforeRoutine(PatchInstance *patch,
|
||||
REG_SET *regs, long userData[8]);
|
||||
|
||||
extern int MemScopeReallocAfterRoutine(PatchInstance *patch, long userData[8],
|
||||
void * returnValue);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* MemScopePartStart - set up patch points and tables for a partition
|
||||
*
|
||||
* This routine sets patch points for allocating and freeing memory.
|
||||
*/
|
||||
extern RTIBool MemScopePartStart(const MemScopeAllocData * const msad,
|
||||
const MemScopeFreeData * const msfd);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* MemScopePartFinish - counterpart to MemScopePartStart
|
||||
*
|
||||
* This routine undoes the actions in MemScopePartStart, reclaiming resources
|
||||
* and removing patches.
|
||||
*/
|
||||
extern void MemScopePartFinish(void);
|
||||
|
||||
|
||||
#endif /* if !MEMSCOPE_NO_PATCHING */
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* MemScopeTargetExit - shut down memscope operations
|
||||
*
|
||||
* This routine is the converse of MemScopeInit(). It performs an orderly
|
||||
* shut down of the tool and releases all memory and system resources it
|
||||
* was using.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
extern void MemScopeTargetExit(void);
|
||||
|
||||
|
||||
extern int MemScopeTimesFullGet(void);
|
||||
|
||||
|
||||
extern void MemScopeCollectionDisable(const void * const dummy);
|
||||
|
||||
|
||||
extern void MemScopeCollectionEnable(const void * const dummy);
|
||||
|
||||
|
||||
extern RTIBool MemScopeTaskIgnore(const WIND_TCB * tid);
|
||||
|
||||
|
||||
/* gcc does not seem to align the char buffer to a word boundary on SH targets,
|
||||
even though this arch will through an exception when we try to read its
|
||||
contents via a casted void * variable.
|
||||
*/
|
||||
#if (CPU_FAMILY == SH)
|
||||
# define BUFFER_ALIGN __attribute__ ((aligned(sizeof(int))))
|
||||
#else
|
||||
# define BUFFER_ALIGN
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
extern void MemScopeMsgSend(const void * const partId, const void * const addr,
|
||||
const int nBytes,
|
||||
const RTP_ID pid, const WIND_TCB * const tid,
|
||||
const int code,
|
||||
const unsigned int group,
|
||||
void *stack[MAX_STACKDEPTH]);
|
||||
|
||||
|
||||
extern void MemScopeCorrelate(const unsigned int triggerNum);
|
||||
|
||||
|
||||
extern RTIBool MemScopeSetTaskIgnore(char * const taskName);
|
||||
|
||||
|
||||
extern RTIBool MemScopeQFreeDataInit (void * qFreeDataAddress);
|
||||
|
||||
|
||||
extern int MemAgentVersionGet(void);
|
||||
|
||||
|
||||
/***************************************************************
|
||||
MemScopeInit \- Track memory allocation on the target.
|
||||
|
||||
PARAMETERS:
|
||||
numMsg - The size of the message queue on the target
|
||||
|
||||
verbosity - Used to indicate debug level. Output goes to stdout.
|
||||
|
||||
stackDepth - The maximum depth of the call stack in the allocation
|
||||
record.
|
||||
|
||||
useWtx - use a purely WTX connection to the target (as opposed to
|
||||
using TCP to get the data)
|
||||
|
||||
pollDelay - use the connecting protocol to poll at certain rate.
|
||||
measured in nanoseconds
|
||||
|
||||
linkPriority - priority of the link task [if useWtx == FALSE]
|
||||
|
||||
wvEnable - whether WindView is enabled or not
|
||||
|
||||
triggerEnable - whether triggering is enabled or not
|
||||
|
||||
textStartAdrs - start address of kernel text region
|
||||
|
||||
textEndAdrs - end address of kernel text region
|
||||
|
||||
RETURN VALUE: 0 for failure, 1 for success.
|
||||
*/
|
||||
extern RTIBool MemScopeInit (const int numMsg, const int verbosity,
|
||||
const UINT stackDepth, const int tcpPortNumber,
|
||||
const UINT pollDelay, const int linkPriority,
|
||||
const RTIBool wvEnable, const RTIBool triggerEnable,
|
||||
void * textStartAdrs,
|
||||
void * textEndAdrs);
|
||||
|
||||
|
||||
extern void MemScopeTracingError(void);
|
||||
|
||||
|
||||
#if !MEMSCOPE_NO_PATCHING
|
||||
|
||||
|
||||
/**
|
||||
* Function installed by patchSet to run just before any calls to realloc().
|
||||
*/
|
||||
extern int MemScopeReallocBeforeRoutine(PatchInstance * patch,
|
||||
REG_SET * regs, long userData[8]);
|
||||
|
||||
|
||||
/**
|
||||
* Function installed by patchSet to run just after any calls to realloc().
|
||||
*/
|
||||
extern int MemScopeReallocAfterRoutine(PatchInstance *patch, long userData[8],
|
||||
void * returnValue);
|
||||
|
||||
|
||||
extern int MemScopeAllocBeforeRoutine(PatchInstance * patch,
|
||||
REG_SET * regs, long userData[8]);
|
||||
|
||||
|
||||
/**
|
||||
* 'Before' routine for memPartFree calls
|
||||
*/
|
||||
extern int MemScopeFreeBeforeRoutine(PatchInstance * patch, REG_SET * regs,
|
||||
long userData[8]);
|
||||
|
||||
|
||||
extern int MemScopeQFreeBeforeRoutine(PatchInstance * patch, REG_SET * regs,
|
||||
long userData[8]);
|
||||
|
||||
|
||||
extern int MemScopeAllocAfterRoutine(PatchInstance *patch, long userData[8],
|
||||
void * returnValue);
|
||||
|
||||
|
||||
extern int MemScopeQFreeAfterRoutine(PatchInstance *patch, long userData[8],
|
||||
void * returnValue);
|
||||
|
||||
|
||||
#endif /* if MEMSCOPE_NO_PATCHING */
|
||||
|
||||
|
||||
extern int MemScopeHeapCheck(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* memscope_pkg_h */
|
||||
@@ -0,0 +1,717 @@
|
||||
/* memscope_old.c - Original target-side support library for MemScope */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002-2012 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01i,08nov12,wzc WIND00387426 - Fix realloc calling stack.
|
||||
01h,05jul12,wzc WIND00357415 - Remove building warnings.
|
||||
01g,29sep11,zlo Use vxWindowsFlush to flush register windows.(WIND00303691)
|
||||
01f,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
01e,11apr11,wzc Fix free memory address in MemScopeRealloc.(CQ:WIND00257341)
|
||||
01d,28sep10,jpb Added memLib.h for memSysPartId.
|
||||
01c,18mar10,flu Modified the code for diab compilation(for simlinux) (CQ:WIND00146073)
|
||||
01b,05mar10,flu Modified the code for diab compilation (CQ:WIND00146073)
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
3.4a,27aug08,mas added vsbConfig.h; changed _WRS_XV_SMP to _WRS_CONFIG_SMP
|
||||
3.3a,29jan07,mas made SMP-compliant
|
||||
1.0, 19mar02,pac Written
|
||||
*/
|
||||
/* $Id: memscope_old.c,v 1.31 2008/04/02 19:25:45 panderse Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Original target-side support library for MemScope
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <logLib.h>
|
||||
#include <string.h>
|
||||
#include <sysLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <vsbConfig.h>
|
||||
#include <memLib.h> /* memSysPartId */
|
||||
#include <private/vmLibP.h>
|
||||
|
||||
#include <st_stacktrace.h>
|
||||
#include <rtitools/rti_wvEvents.h>
|
||||
|
||||
#pragma begin_package
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <types/vxCpu.h>
|
||||
#if (CPU == SIMNT) || (CPU == SIMSPARCSOLARIS) || (CPU == SIMLINUX)
|
||||
# define MEMSCOPE_NO_PATCHING (1)
|
||||
#else
|
||||
# define MEMSCOPE_NO_PATCHING (0)
|
||||
#endif
|
||||
#pragma end_package
|
||||
|
||||
#ifdef __DCC__
|
||||
#if (CPU==SIMSPARCSOLARIS)
|
||||
asm volatile int getRegData (volatile unsigned int *address_p)
|
||||
{
|
||||
%reg address_p
|
||||
!
|
||||
st %sp, [address_p]
|
||||
|
||||
}
|
||||
#endif /* CPU==SIMSPARCSOLARIS */
|
||||
|
||||
#if (CPU==SIMNT) || (CPU==SIMLINUX)
|
||||
asm volatile int getRegDataLinux (volatile unsigned int *address_p)
|
||||
{
|
||||
%mem address_p
|
||||
!
|
||||
movl %ebp, (address_p)
|
||||
}
|
||||
#endif /* (CPU==SIMNT) || (CPU==SIMLINUX) */
|
||||
|
||||
#endif /* __DCC__ */
|
||||
|
||||
#include "memscope.pkg.h"
|
||||
|
||||
#if defined(CONTEXT_SESSION_LOGGING)
|
||||
# include "sessionLog.h"
|
||||
#endif
|
||||
|
||||
#if MEMSCOPE_NO_PATCHING
|
||||
# include <private/memPartLibP.h>
|
||||
# define memSysPart ((PARTITION *) memSysPartId)
|
||||
#endif /* if MEMSCOPE_NO_PATCHING */
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
|
||||
#if MEMSCOPE_NO_PATCHING
|
||||
Private RTIBool memScopePatch = RTI_FALSE;
|
||||
|
||||
package
|
||||
void * MemScopeAllocate(const unsigned int nBytes, const void * const func)
|
||||
{
|
||||
void *pBlock;
|
||||
WIND_TCB *tid;
|
||||
void *stack[MAX_STACKDEPTH];
|
||||
PART_ID partId;
|
||||
ST_context temp1, temp2;
|
||||
ST_context *context = &temp1;
|
||||
ST_context *parent = &temp2;
|
||||
ST_context *tempContext;
|
||||
REG_SET regs;
|
||||
int i;
|
||||
|
||||
partId = memSysPart;
|
||||
pBlock = memPartAlloc(partId, nBytes);
|
||||
|
||||
if (MemScope.collectionEnabled == RTI_FALSE) {
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
/* if allocation fails, notify windview & triggers and return 0 */
|
||||
if (pBlock == 0) {
|
||||
if (MemScope.wvEnable == RTI_TRUE) {
|
||||
RtiTools_WvEventII(EVENT_MEM_FAILEDALLOC, (UINT32) partId, nBytes);
|
||||
}
|
||||
|
||||
if (MemScope.triggerEnable == RTI_TRUE) {
|
||||
RtiTools_triggerPost(EVENT_MEM_FAILEDALLOC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MemScope.msgQId != NULL) {
|
||||
tid = taskIdCurrent;
|
||||
if (!MemScopeTaskIgnore(tid)) {
|
||||
#if (CPU==SIMNT) || (CPU==SIMLINUX)
|
||||
unsigned int fpReg = 0;
|
||||
|
||||
#ifdef __DCC__
|
||||
getRegDataLinux(&fpReg);
|
||||
#else
|
||||
asm("movl %%ebp, %0" : "=r" (fpReg) );
|
||||
#endif /* __DCC__ */
|
||||
|
||||
regs.reg_pc = (void *) func;
|
||||
regs.reg_fp = fpReg;
|
||||
regs.reg_sp = fpReg+sizeof(void *);
|
||||
|
||||
#elif CPU==SIMSPARCSOLARIS
|
||||
unsigned int spReg;
|
||||
|
||||
/* Flush the windows. */
|
||||
vxWindowsFlush();
|
||||
#ifdef __DCC__
|
||||
getRegData(&spReg);
|
||||
#else
|
||||
asm("mov %%sp, %0" : "=r" (spReg) );
|
||||
#endif
|
||||
regs.reg_sp = spReg;
|
||||
regs.reg_out[7] = (long) func;
|
||||
/* setting the pc value like this isn't technically correct,
|
||||
but it's not actually used by the simsolaris tracing logic,
|
||||
and it is needed since the architecture-independent algorithm
|
||||
now verifies the pc values before it traces. */
|
||||
regs.reg_pc = (void *) func;
|
||||
#else
|
||||
# error "MemScope_old not available for this cpu type!"
|
||||
#endif
|
||||
|
||||
#if defined(CONTEXT_SESSION_LOGGING)
|
||||
/* Create a new session log */
|
||||
newSession();
|
||||
#endif
|
||||
ST_context_create(®s, (unsigned long) taskIdCurrent,
|
||||
RTI_TRUE, context);
|
||||
|
||||
stack[0] = (void *) func;
|
||||
|
||||
/* If this fails, it will be caught in the next loop -
|
||||
* need to skip two
|
||||
*/
|
||||
if (ST_CallingContextGet(context, parent) ==
|
||||
ST_CONTEXT_OK)
|
||||
{
|
||||
/* skip one */
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
|
||||
if (ST_CallingContextGet(context, parent) ==
|
||||
ST_CONTEXT_OK)
|
||||
{
|
||||
|
||||
/* skip one */
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < MemScope.stackDepth; ++i) {
|
||||
const int status =
|
||||
ST_CallingContextGet(context, parent);
|
||||
|
||||
if ( status == ST_CONTEXT_OK ) {
|
||||
stack[i] = (void *)parent->pc;
|
||||
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
} else if ( status == ST_CONTEXT_EXCEPTION_TOP) {
|
||||
stack[i] = (void *)parent->pc;
|
||||
parent->pc = parent->gpregs[REG_LR];
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
} else if ( status == ST_CONTEXT_TOP) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
break;
|
||||
}
|
||||
else if ( status == ST_CONTEXT_ERROR ) {
|
||||
#if defined(CONTEXT_SESSION_LOGGING)
|
||||
saveSession();
|
||||
#endif
|
||||
stack[i++] = (void *)MemScopeTracingError;
|
||||
if (i < MemScope.stackDepth) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
v1printf("MemScope: Context engine returned unknown value (%d).", status);
|
||||
#if defined(CONTEXT_SESSION_LOGGING)
|
||||
saveSession();
|
||||
#endif
|
||||
stack[i++] = (void *)MemScopeTracingError;
|
||||
if (i < MemScope.stackDepth) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MemScopeMsgSend(partId, pBlock, nBytes, tid->rtpId, tid,
|
||||
MEMSCOPE_ALLOC, 0, stack);
|
||||
|
||||
if (MemScope.wvEnable == RTI_TRUE) {
|
||||
RtiTools_WvEventIII(EVENT_MEM_ALLOC, (UINT32) pBlock,
|
||||
(UINT32) partId, nBytes);
|
||||
}
|
||||
|
||||
if (MemScope.triggerEnable == RTI_TRUE) {
|
||||
RtiTools_triggerPost(EVENT_MEM_ALLOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (pBlock);
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
void *MemScopeMalloc(unsigned nBytes)
|
||||
{
|
||||
void *pBlock;
|
||||
|
||||
pBlock = MemScopeAllocate(nBytes, malloc);
|
||||
|
||||
return(pBlock);
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
void MemScopeFree(void *pBlock)
|
||||
{
|
||||
WIND_TCB *tid;
|
||||
void *stack[MAX_STACKDEPTH];
|
||||
int i;
|
||||
PART_ID partId;
|
||||
ST_context temp1, temp2;
|
||||
ST_context *context = &temp1;
|
||||
ST_context *parent = &temp2;
|
||||
ST_context *tempContext;
|
||||
REG_SET regs;
|
||||
|
||||
partId = memSysPart;
|
||||
memPartFree(partId, pBlock);
|
||||
|
||||
if (MemScope.collectionEnabled == RTI_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MemScope.msgQId != NULL) {
|
||||
tid = taskIdCurrent;
|
||||
#if defined(CONTEXT_SESSION_LOGGING)
|
||||
/* Create a new session log */
|
||||
newSession();
|
||||
#endif
|
||||
|
||||
if (!MemScopeTaskIgnore(tid)) {
|
||||
#if (CPU==SIMNT) || (CPU==SIMLINUX)
|
||||
unsigned int fpReg = 0;
|
||||
|
||||
#ifdef __DCC__
|
||||
getRegDataLinux(&fpReg);
|
||||
#else
|
||||
asm("movl %%ebp, %0" : "=r" (fpReg) );
|
||||
#endif /*__DCC__ */
|
||||
|
||||
regs.reg_pc = (void *)free;
|
||||
regs.reg_fp = fpReg;
|
||||
regs.reg_sp = fpReg+sizeof(void *);
|
||||
|
||||
#elif CPU==SIMSPARCSOLARIS
|
||||
unsigned int spReg;
|
||||
|
||||
/* Flush the windows. */
|
||||
vxWindowsFlush();
|
||||
#ifdef __DCC__
|
||||
getRegData(&spReg);
|
||||
#else
|
||||
asm("mov %%sp, %0" : "=r" (spReg) );
|
||||
#endif
|
||||
regs.reg_sp = spReg;
|
||||
regs.reg_out[7] = (long) free;
|
||||
/* setting the pc value like this isn't technically correct,
|
||||
but it's not actually used by the simsolaris tracing logic,
|
||||
and it is needed since the architecture-independent algorithm
|
||||
now verifies the pc values before it traces. */
|
||||
regs.reg_pc = (void *) free;
|
||||
#else
|
||||
# error "MemScope_old not available for this cpu type!"
|
||||
#endif
|
||||
stack[0] = free;
|
||||
|
||||
ST_context_create(®s, (unsigned long) taskIdCurrent,
|
||||
RTI_TRUE, context);
|
||||
|
||||
/* If this fails, it will be caught in the loop */
|
||||
if (ST_CallingContextGet(context, parent) ==
|
||||
ST_CONTEXT_OK) {
|
||||
|
||||
/* skip one */
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
}
|
||||
|
||||
for (i = 1; i < MemScope.stackDepth; ++i) {
|
||||
const int status =
|
||||
ST_CallingContextGet(context, parent);
|
||||
|
||||
if ( status == ST_CONTEXT_OK ) {
|
||||
stack[i] = (void *)parent->pc;
|
||||
#if defined(CONTEXT_SESSION_LOGGING)
|
||||
if (parent->pc == (void *) 0xeeeeeeee) {
|
||||
/* Create a new session log */
|
||||
saveSession();
|
||||
}
|
||||
#endif
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
}
|
||||
else if ( status == ST_CONTEXT_TOP) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
break;
|
||||
} else if ( status == ST_CONTEXT_EXCEPTION_TOP) {
|
||||
stack[i] = (void *)parent->pc;
|
||||
parent->pc = parent->gpregs[REG_LR];
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
} else if ( status == ST_CONTEXT_ERROR ) {
|
||||
stack[i++] = (void *)MemScopeTracingError;
|
||||
if (i < MemScope.stackDepth) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
v1printf("MemScope: Context engine returned unknown value (%d).", status);
|
||||
stack[i++] = (void *)MemScopeTracingError;
|
||||
if (i < MemScope.stackDepth) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MemScopeMsgSend(partId, pBlock, -1, tid->rtpId, tid, MEMSCOPE_FREE,
|
||||
0, stack);
|
||||
|
||||
if (MemScope.wvEnable == RTI_TRUE) {
|
||||
RtiTools_WvEventII(EVENT_MEM_FREE, (UINT32)pBlock,
|
||||
(UINT32) partId);
|
||||
}
|
||||
|
||||
if (MemScope.triggerEnable == RTI_TRUE) {
|
||||
RtiTools_triggerPost(EVENT_MEM_FREE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
void *MemScopeCalloc(unsigned nItems, unsigned nBytes)
|
||||
{
|
||||
void *pBlock;
|
||||
int total = nItems*nBytes;
|
||||
|
||||
if ((pBlock = MemScopeAllocate(total, calloc)) != NULL) {
|
||||
memset(pBlock, 0, total);
|
||||
}
|
||||
return(pBlock);
|
||||
}
|
||||
|
||||
|
||||
package
|
||||
void *MemScopeRealloc(void *pBlock, unsigned newSize)
|
||||
{
|
||||
WIND_TCB *tid;
|
||||
void *stack[MAX_STACKDEPTH];
|
||||
PART_ID partId = memSysPartId;
|
||||
ST_context temp1, temp2;
|
||||
ST_context *context = &temp1;
|
||||
ST_context *parent = &temp2;
|
||||
ST_context *tempContext;
|
||||
REG_SET regs;
|
||||
int i;
|
||||
void * freeAddr = pBlock;
|
||||
|
||||
if (pBlock == 0) {
|
||||
return ((char *) MemScopeAllocate(newSize, realloc));
|
||||
}
|
||||
|
||||
/* if reallocation fails, notify windview & triggers and return 0 */
|
||||
if ((pBlock = memPartRealloc(partId, pBlock, newSize)) == 0) {
|
||||
if (MemScope.wvEnable == RTI_TRUE) {
|
||||
RtiTools_WvEventII(EVENT_MEM_FAILEDALLOC, (UINT32)partId, newSize);
|
||||
}
|
||||
|
||||
if (MemScope.triggerEnable == RTI_TRUE) {
|
||||
RtiTools_triggerPost(EVENT_MEM_FAILEDALLOC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MemScope.collectionEnabled == RTI_FALSE) {
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
if (MemScope.msgQId != NULL) {
|
||||
tid = taskIdCurrent;
|
||||
if (!MemScopeTaskIgnore(tid)) {
|
||||
#if (CPU==SIMNT) || (CPU==SIMLINUX)
|
||||
unsigned int fpReg = 0;
|
||||
|
||||
#ifdef __DCC__
|
||||
getRegDataLinux(&fpReg);
|
||||
#else
|
||||
asm("movl %%ebp, %0" : "=r" (fpReg) );
|
||||
#endif /*__DCC__*/
|
||||
|
||||
regs.reg_pc = (void *)realloc;
|
||||
regs.reg_fp = fpReg;
|
||||
regs.reg_sp = fpReg+sizeof(void *);
|
||||
|
||||
#elif CPU==SIMSPARCSOLARIS
|
||||
unsigned int spReg;
|
||||
|
||||
/* Flush the windows. */
|
||||
vxWindowsFlush();
|
||||
#ifdef __DCC__
|
||||
getRegData(&spReg);
|
||||
#else
|
||||
asm("mov %%sp, %0" : "=r" (spReg) );
|
||||
#endif
|
||||
regs.reg_sp = spReg;
|
||||
regs.reg_out[7] = (long) realloc;
|
||||
/* setting the pc value like this isn't technically correct,
|
||||
but it's not actually used by the simsolaris tracing logic,
|
||||
and it is needed since the architecture-independent algorithm
|
||||
now verifies the pc values before it traces. */
|
||||
regs.reg_pc = (void *) realloc;
|
||||
#else
|
||||
# error "MemScope_old not available for this cpu type!"
|
||||
#endif
|
||||
|
||||
ST_context_create(®s, (unsigned long) taskIdCurrent,
|
||||
RTI_TRUE, context);
|
||||
|
||||
/* If this fails, it will be caught in the loop */
|
||||
if (ST_CallingContextGet(context, parent) ==
|
||||
ST_CONTEXT_OK) {
|
||||
|
||||
/* skip one */
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
}
|
||||
|
||||
for (i = 1; i < MemScope.stackDepth; ++i) {
|
||||
const int status =
|
||||
ST_CallingContextGet(context, parent);
|
||||
|
||||
if ( status == ST_CONTEXT_OK ) {
|
||||
stack[i] = (void *)parent->pc;
|
||||
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
}
|
||||
else if ( status == ST_CONTEXT_TOP) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
break;
|
||||
} else if ( status == ST_CONTEXT_EXCEPTION_TOP) {
|
||||
stack[i] = (void *)parent->pc;
|
||||
parent->pc = parent->gpregs[REG_LR];
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
} else if ( status == ST_CONTEXT_ERROR ) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
logMsg("Error tracing context.\n");
|
||||
break;
|
||||
} else {
|
||||
v1printf("MemScope: Context engine returned unknown value (%d).", status);
|
||||
stack[i++] = (void *)MemScopeTracingError;
|
||||
if (i < MemScope.stackDepth) {
|
||||
stack[i] = ENDOFSTACK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
partId = memSysPart;
|
||||
|
||||
stack[0] = realloc;
|
||||
MemScopeMsgSend(partId, freeAddr, -1, tid->rtpId, tid, MEMSCOPE_FREE,
|
||||
0, stack);
|
||||
stack[0] = realloc;
|
||||
MemScopeMsgSend(partId, pBlock, newSize, tid->rtpId, tid,
|
||||
MEMSCOPE_ALLOC, 0, stack);
|
||||
|
||||
if (MemScope.wvEnable == RTI_TRUE) {
|
||||
RtiTools_WvEventII(EVENT_MEM_FREE, (UINT32)pBlock,
|
||||
(UINT32) partId);
|
||||
}
|
||||
|
||||
if (MemScope.triggerEnable == RTI_TRUE) {
|
||||
RtiTools_triggerPost(EVENT_MEM_FREE);
|
||||
}
|
||||
|
||||
if (MemScope.wvEnable == RTI_TRUE) {
|
||||
RtiTools_WvEventIII(EVENT_MEM_ALLOC, (UINT32) pBlock,
|
||||
(UINT32) partId, newSize);
|
||||
}
|
||||
|
||||
if (MemScope.triggerEnable == RTI_TRUE) {
|
||||
RtiTools_triggerPost(EVENT_MEM_ALLOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(pBlock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Private
|
||||
STATUS MemNoPatchInstall(const void * const newRtn,
|
||||
void * const oldRtn,
|
||||
char * pStorage)
|
||||
{
|
||||
#if (CPU==SIMNT) || (CPU==SIMLINUX)
|
||||
char buffer[7];
|
||||
bcopy (oldRtn, pStorage, 8); /* store original instruction sequence */
|
||||
buffer[0] = 0xb8; /* mov eax, newRtn */
|
||||
*((int *) &buffer[1]) = (unsigned long) newRtn;
|
||||
buffer[6] = 0xe0;
|
||||
buffer[5] = 0xff;
|
||||
|
||||
VM_CONTEXT_BUFFER_WRITE(0, buffer, oldRtn, 7);
|
||||
#elif CPU == SIMSPARCSOLARIS
|
||||
unsigned int inst;
|
||||
|
||||
/* asm(" sethi %%hi(0x12345678), %%g1
|
||||
jmp %%g1 + %%lo (0x12345678)
|
||||
nop
|
||||
");
|
||||
*/
|
||||
bcopy (oldRtn, pStorage, 12); /* store original instruction sequence */
|
||||
|
||||
inst = 0x03000000 | ((unsigned) newRtn >> 10); /* sethi */
|
||||
VM_CONTEXT_BUFFER_WRITE(0, &inst, oldRtn, 4);
|
||||
|
||||
inst = 0x81c06000 | ((unsigned) newRtn & 0x000003ff); /* jmp */
|
||||
VM_CONTEXT_BUFFER_WRITE(0, &inst, ((unsigned long)oldRtn + 4), 4);
|
||||
|
||||
inst = 0x01000000; /* nop */
|
||||
VM_CONTEXT_BUFFER_WRITE(0, &inst, ((unsigned long)oldRtn + 8), 4);
|
||||
|
||||
#else
|
||||
# error "Unsupported MemNoPatchInstall architecture"
|
||||
#endif
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/* Storage for original instructions that were overwritten */
|
||||
|
||||
Private char orgMalloc[16];
|
||||
Private char orgCalloc[16];
|
||||
Private char orgRealloc[16];
|
||||
Private char orgFree[16];
|
||||
|
||||
|
||||
Package
|
||||
RTIBool MemScopeOldStart(void)
|
||||
{
|
||||
taskDelay(sysClkRateGet());
|
||||
#ifdef SMP_CONFIG
|
||||
taskCpuLock();
|
||||
#else
|
||||
taskLock();
|
||||
#endif
|
||||
if (!memScopePatch) {
|
||||
MemNoPatchInstall(MemScopeMalloc, malloc, orgMalloc);
|
||||
MemNoPatchInstall(MemScopeCalloc, calloc, orgCalloc);
|
||||
MemNoPatchInstall(MemScopeRealloc, realloc, orgRealloc);
|
||||
MemNoPatchInstall(MemScopeFree, free, orgFree);
|
||||
}
|
||||
|
||||
memScopePatch = RTI_TRUE;
|
||||
#ifdef SMP_CONFIG
|
||||
taskCpuUnlock();
|
||||
#else
|
||||
taskUnlock();
|
||||
#endif
|
||||
|
||||
/* enable normal operation after full and complete initialization */
|
||||
#ifdef SMP_CONFIG
|
||||
vxAtomicSet ((atomic_t*) &MemScope.collectionEnabled, RTI_TRUE);
|
||||
#else
|
||||
MemScope.collectionEnabled = RTI_TRUE;
|
||||
#endif
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
STATUS MemNoPatchRemove(const void * const pOrgRtn,
|
||||
void * const oldRtn)
|
||||
{
|
||||
#if (CPU==SIMNT) || (CPU==SIMLINUX)
|
||||
VM_CONTEXT_BUFFER_WRITE(0, pOrgRtn, oldRtn, 8);
|
||||
#elif CPU == SIMSPARCSOLARIS
|
||||
VM_CONTEXT_BUFFER_WRITE(0, pOrgRtn, oldRtn, 12);
|
||||
#else
|
||||
# error "Unsupported MemNoPatchRemove architecture"
|
||||
#endif
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void MemScopePartFinish(void)
|
||||
{
|
||||
/* enable normal operation after full and complete initialization */
|
||||
#ifdef SMP_CONFIG
|
||||
vxAtomicSet ((atomic_t*) &MemScope.collectionEnabled, RTI_TRUE);
|
||||
#else
|
||||
MemScope.collectionEnabled = RTI_TRUE;
|
||||
#endif
|
||||
#ifdef SMP_CONFIG
|
||||
taskCpuLock();
|
||||
#else
|
||||
taskLock();
|
||||
#endif
|
||||
if (memScopePatch) {
|
||||
MemNoPatchRemove(orgMalloc, malloc);
|
||||
MemNoPatchRemove(orgCalloc, calloc);
|
||||
MemNoPatchRemove(orgRealloc, realloc);
|
||||
MemNoPatchRemove(orgFree, free);
|
||||
}
|
||||
|
||||
memScopePatch = RTI_FALSE;
|
||||
#ifdef SMP_CONFIG
|
||||
taskCpuUnlock();
|
||||
#else
|
||||
taskUnlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* if MEMSCOPE_NO_PATCHING */
|
||||
|
||||
|
||||
Package
|
||||
RTIBool MemScopePatchCapableGet(void)
|
||||
{
|
||||
return (MEMSCOPE_NO_PATCHING == 0);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/* memscope_old.pkg.h - built from: memscope_old.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef memscope_old_pkg_h
|
||||
#define memscope_old_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <types/vxCpu.h>
|
||||
#if (CPU == SIMNT) || (CPU == SIMSPARCSOLARIS) || (CPU == SIMLINUX)
|
||||
# define MEMSCOPE_NO_PATCHING (1)
|
||||
#else
|
||||
# define MEMSCOPE_NO_PATCHING (0)
|
||||
#endif
|
||||
|
||||
|
||||
extern void * MemScopeAllocate(const unsigned int nBytes, const void * const func);
|
||||
|
||||
|
||||
extern void *MemScopeMalloc(unsigned nBytes);
|
||||
|
||||
|
||||
extern void MemScopeFree(void *pBlock);
|
||||
|
||||
|
||||
extern void *MemScopeCalloc(unsigned nItems, unsigned nBytes);
|
||||
|
||||
|
||||
extern void *MemScopeRealloc(void *pBlock, unsigned newSize);
|
||||
|
||||
|
||||
extern RTIBool MemScopeOldStart(void);
|
||||
|
||||
|
||||
extern void MemScopePartFinish(void);
|
||||
|
||||
|
||||
extern RTIBool MemScopePatchCapableGet(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* memscope_old_pkg_h */
|
||||
@@ -0,0 +1,310 @@
|
||||
/* rtp_support.c - Target-side RTP support library for MemScope */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2007, 2009-2010, 2012 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
-------------------
|
||||
01d,05jul12,wzc WIND00357415 - Remove building warnings.
|
||||
01c,09apr10,jpb Renamed _func_sdUnmapAll to _func_rtpSdUnmapAll.
|
||||
01c,30mar10,jmp cleared SYMBOL_DESC structure before using it.
|
||||
01b,09nov09,pad Aligned patchRTP() to the expected signature for objEach().
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
3b,12mar09,jmp Replaced old style symXxxFind routine by symFind().
|
||||
3.3a,29jan07,mas made SMP-compliant
|
||||
3.0, 09nov05,pca Written
|
||||
*/
|
||||
/* $Id: rtp_support.c,v 1.14 2007/11/13 20:47:32 dlerner Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Target-side RTP support library for MemScope
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <rtilib/vxVersions.h>
|
||||
#include "memscope_old.pkg.h"
|
||||
|
||||
#if (VXWORKS_VERSION_6_0_OR_BETTER) && !MEMSCOPE_NO_PATCHING
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <logLib.h>
|
||||
#include <symbol.h>
|
||||
#include <symLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <private/kernelBaseLibP.h>
|
||||
#include <private/rtpLibP.h>
|
||||
#include <private/rtpUtilLibP.h>
|
||||
#if VXWORKS_VERSION_6_6_OR_BETTER
|
||||
# include <vxAtomicLib.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include "memscope.pkg.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
/* defined in rtpUtilLib.c, but not in any header files, so we need our own
|
||||
extern. */
|
||||
extern SYMTAB_ID rtpSymTblIdGet(RTP_ID rtpId);
|
||||
|
||||
|
||||
Private void MemScopeRtpCreateHook(const RTP_ID rtpId);
|
||||
|
||||
|
||||
Private
|
||||
/**
|
||||
*
|
||||
*/
|
||||
BOOL patchRTP(OBJ_ID objId, void * pArg)
|
||||
{
|
||||
if (objId != kernelId) {
|
||||
v2printf("Attaching to RTP %x\n", objId);
|
||||
MemScopeRtpCreateHook(objId);
|
||||
} else {
|
||||
v3printf("Ignoring kernel RTP %x\n", objId);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MemScopeInitRtpSupport(void)
|
||||
{
|
||||
if (0 == _func_rtpSdUnmapAll) {
|
||||
v1printf("MemScope: No shared data region support found in the running kernel.\n"
|
||||
"\tNo heap allocation data will be collected from RTPs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_func_rtpInitCompleteHookAdd != 0) {
|
||||
if (ERROR == (*_func_rtpInitCompleteHookAdd) (MemScopeRtpCreateHook, FALSE)) {
|
||||
v0printf("MemScope: Error adding rtp creation hook, no data "
|
||||
"will be collected from RTPs\n");
|
||||
}
|
||||
} else {
|
||||
v1printf("MemScope: No rtp hook support found, no data will be "
|
||||
"collected from newly spawned RTPs\n");
|
||||
}
|
||||
|
||||
objEach(windRtpClass, patchRTP, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MemScopeRemoveRtpSupport(void)
|
||||
{
|
||||
/* remove our rtp data collection callbacks */
|
||||
if (_func_rtpInitCompleteHookDelete != 0) {
|
||||
if (ERROR == (*_func_rtpInitCompleteHookDelete) (MemScopeRtpCreateHook)) {
|
||||
/* fail silently */
|
||||
/* logMsg(""); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULT_HEAP_RELEASE "memPartFreeInternal"
|
||||
#define DEFAULT_HEAP_RELEASE2 "_memPartFreeInternal"
|
||||
#define DEFAULT_HEAP_RELEASE3 "memPartFree"
|
||||
#define DEFAULT_HEAP_RELEASE4 "_memPartFree"
|
||||
#define DEFAULT_HEAP_ALLOC "memPartAlignedAllocInternal"
|
||||
#define DEFAULT_HEAP_ALLOC2 "_memPartAlignedAllocInternal"
|
||||
#define DEFAULT_HEAP_ALLOC3 "memPartAlignedAlloc"
|
||||
#define DEFAULT_HEAP_ALLOC4 "_memPartAlignedAlloc"
|
||||
#define DEFAULT_HEAP_REALLOC "memPartReallocInternal"
|
||||
#define DEFAULT_HEAP_REALLOC2 "_memPartReallocInternal"
|
||||
#define DEFAULT_HEAP_REALLOC3 "memPartRealloc"
|
||||
#define DEFAULT_HEAP_REALLOC4 "_memPartRealloc"
|
||||
|
||||
Private
|
||||
void MemScopeRtpCreateHook(const RTP_ID rtpId)
|
||||
{
|
||||
SYMBOL_DESC symbolDesc; /* symFind() descriptor */
|
||||
SYMTAB_ID symtab;
|
||||
char * allocAddress = NULL;
|
||||
char * freeAddress = NULL;
|
||||
char * reallocAddress = NULL;
|
||||
#if VXWORKS_VERSION_6_6_OR_BETTER
|
||||
static atomic_t group_id_pool = 1;
|
||||
atomicVal_t group;
|
||||
#else
|
||||
static unsigned int group_id_pool = 1;
|
||||
unsigned int group;
|
||||
#endif
|
||||
|
||||
symtab = (SYMTAB_ID) rtpSymTblIdGet(rtpId);
|
||||
if (0 == symtab) {
|
||||
v1printf("Failed to find symbol table for RTP %p\n", rtpId);
|
||||
return;
|
||||
}
|
||||
|
||||
v3printf("Kernel RTP: %p; RTP_ID 0x%x:\tsymTab = 0x%x\n", kernelIdGet(),
|
||||
rtpId, symtab);
|
||||
|
||||
/* first find the addresses we want to patch */
|
||||
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_RELEASE;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_RELEASE2;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_RELEASE3;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_RELEASE4;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
v1printf("Error looking up RTP heap release function \""
|
||||
DEFAULT_HEAP_RELEASE3 "\"(%p): 0x%x\n",rtpId,errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeAddress = symbolDesc.value;
|
||||
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_ALLOC;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_ALLOC2;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_ALLOC3;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_ALLOC4;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
v1printf("Error looking up RTP heap allocation function \""
|
||||
DEFAULT_HEAP_ALLOC3 "\"(%p): 0x%x\n",rtpId,errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allocAddress = symbolDesc.value;
|
||||
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_REALLOC;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_REALLOC2;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_REALLOC3;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
memset (&symbolDesc, 0, sizeof (SYMBOL_DESC));
|
||||
symbolDesc.mask = SYM_FIND_BY_NAME;
|
||||
symbolDesc.name = DEFAULT_HEAP_REALLOC4;
|
||||
|
||||
if (symFind (symtab, &symbolDesc) == ERROR)
|
||||
{
|
||||
v1printf("Error looking up RTP heap reallocation function \""
|
||||
DEFAULT_HEAP_REALLOC3 "\"(%p)\n", rtpId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reallocAddress = symbolDesc.value;
|
||||
|
||||
#if VXWORKS_VERSION_6_6_OR_BETTER
|
||||
group = vxAtomicInc (&group_id_pool);
|
||||
#else
|
||||
taskLock();
|
||||
group = ++group_id_pool;
|
||||
taskUnlock();
|
||||
#endif
|
||||
/* now apply the patches */
|
||||
if (!RtiTools_PatchFunctionSet(freeAddress, rtpId,
|
||||
MemScopeFreeBeforeRoutine, NULL,
|
||||
(void*)group, 0, (unsigned long) &MemScope))
|
||||
{
|
||||
v1printf("Can't patch " DEFAULT_HEAP_RELEASE " @ %x\n", freeAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RtiTools_PatchFunctionSet(allocAddress, rtpId,
|
||||
MemScopeAllocBeforeRoutine,
|
||||
MemScopeAllocAfterRoutine,
|
||||
(void*)group, 0, (unsigned long) &MemScope))
|
||||
{
|
||||
RtiTools_PatchUnset(freeAddress, (unsigned long)rtpId, RTI_TRUE);
|
||||
v1printf("Can't patch " DEFAULT_HEAP_ALLOC " @ %x\n", allocAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RtiTools_PatchFunctionSet(reallocAddress, rtpId,
|
||||
MemScopeReallocBeforeRoutine,
|
||||
MemScopeReallocAfterRoutine,
|
||||
(void*)group, 0, (unsigned long) &MemScope))
|
||||
{
|
||||
RtiTools_PatchUnset(freeAddress, (unsigned long)rtpId, RTI_TRUE);
|
||||
RtiTools_PatchUnset(allocAddress, (unsigned long)rtpId, RTI_TRUE);
|
||||
v1printf("Can't patch " DEFAULT_HEAP_REALLOC " @ %x\n", reallocAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
/* tests */
|
||||
/*
|
||||
if (ERROR == symFindByName(symtab, "memPartAlignedAllocInternal", &freeAddress, &type)) {
|
||||
logMsg("Error looking up\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/* rtp_support.pkg.h - built from: rtp_support.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rtp_support_pkg_h
|
||||
#define rtp_support_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern void MemScopeInitRtpSupport(void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern void MemScopeRemoveRtpSupport(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rtp_support_pkg_h */
|
||||
@@ -0,0 +1,303 @@
|
||||
/* wtxcalls - functions meant to be called by the wtx link. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
3.4a,27aug08,mas added vsbConfig.h; changed _WRS_XV_SMP to _WRS_CONFIG_SMP
|
||||
3.3a,29jan07,mas made SMP-compliant
|
||||
1.0, 20feb02,pca Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Functions meant to be called by the wtx link.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <errnoLib.h>
|
||||
#include <logLib.h>
|
||||
#include <vsbConfig.h>
|
||||
#include <private/kernelBaseLibP.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <rtilib/vxVersions.h>
|
||||
#if !VXWORKS_VERSION_6_0_OR_BETTER
|
||||
# include <rtitools/heapCheck.h>
|
||||
#endif
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
#include "memscope.pkg.h"
|
||||
#include "memlinkcomm.pkg.h"
|
||||
#include "memscope_old.pkg.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#define MEMSCOPE_DEBUG_WTX_LINK (0)
|
||||
|
||||
#pragma begin_public
|
||||
#define MEMSCOPE_BATCH_SIZE (30)
|
||||
#define MAX_BATCH_MEMSCOPE_MSG_LEN (MEMSCOPE_BATCH_SIZE * MAX_MEMSCOPE_MSG_LEN + 4)
|
||||
|
||||
|
||||
#define MEMSCOPE_ERROR (-2)
|
||||
#define MEMSCOPE_NO_MSG (-1)
|
||||
#define MEMSCOPE_MORE_MSG (2)
|
||||
#pragma end_public
|
||||
|
||||
#define dprintf if (MEMSCOPE_DEBUG_WTX_LINK) logMsg
|
||||
|
||||
/**
|
||||
* Get kernel RTP id
|
||||
*/
|
||||
unsigned int MemScopeGetKernelId(void)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
return (unsigned int) kernelIdGet();
|
||||
#else
|
||||
return (unsigned int) kernelId;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned long MemScopeStackDepthGet(void)
|
||||
{
|
||||
dprintf("MemScopeStackDepthGet: %i\n", (unsigned long)MemScope.stackDepth);
|
||||
dprintf("\tmsgLen: %d\n", MemScope.msgLen);
|
||||
return((unsigned long)MemScope.stackDepth);
|
||||
}
|
||||
|
||||
|
||||
unsigned long MemLinkWtxOverflows(void)
|
||||
{
|
||||
dprintf("MemLinkWtxOverflows: %d\n", MemScope.timesQFull);
|
||||
return((unsigned long)MemScope.timesQFull);
|
||||
}
|
||||
|
||||
|
||||
unsigned long MemScopeAddrGet(void)
|
||||
{
|
||||
dprintf("MemScopeAddrGet:\n");
|
||||
if (MemScope.msgQId == 0) {
|
||||
if (MemScope.stackDepth != 0) {
|
||||
/* indicates to the host that the msgQCreate failed */
|
||||
return (0);
|
||||
} else {
|
||||
/* indicates that MemScopeInit was not run */
|
||||
return (unsigned long) -1L;
|
||||
}
|
||||
} else {
|
||||
return((unsigned long) MemScope.wtxRecvBuff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long MemScopeBufferGet(void)
|
||||
{
|
||||
dprintf("MemScopeBufferGet:\n");
|
||||
if (MemScope.msgQId == 0) {
|
||||
if (MemScope.stackDepth != 0) {
|
||||
logMsg("MemScopeBufferGet: no buffer!\n");
|
||||
/* indicates to the host that the msgQCreate failed */
|
||||
return (0);
|
||||
} else {
|
||||
logMsg("MemScopeBufferGet: never initialized\n");
|
||||
/* indicates that MemScopeInit was not run */
|
||||
return (unsigned long) -1L;
|
||||
}
|
||||
} else {
|
||||
dprintf("\t0x%x\n", MemScope.wtxRecvBuff);
|
||||
return((unsigned long)MemScope.wtxRecvBuff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MemScopeMsgGet(void)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
char *ptr;
|
||||
int numMsg;
|
||||
|
||||
dprintf("MemScopeMsgGet:\n");
|
||||
if (MemScope.msgQId == 0) {
|
||||
return(MEMSCOPE_ERROR);
|
||||
}
|
||||
|
||||
ptr = MemScope.wtxRecvBuff;
|
||||
numMsg = msgQNumMsgs(MemScope.msgQId);
|
||||
if (numMsg == ERROR) {
|
||||
logMsg("Error getting memscope records..\n");
|
||||
return MEMSCOPE_ERROR;
|
||||
}
|
||||
|
||||
if ((numMsg = msgQNumMsgs(MemScope.msgQId)) > MEMSCOPE_BATCH_SIZE) {
|
||||
numMsg = MEMSCOPE_BATCH_SIZE;
|
||||
}
|
||||
|
||||
dprintf("\tnumMsg: %d\n", numMsg);
|
||||
|
||||
for (i = 0; i < numMsg; i++) {
|
||||
status = msgQReceive(MemScope.msgQId, ptr, MemScope.msgLen, NO_WAIT);
|
||||
if (status == ERROR) {
|
||||
if (errno == S_objLib_OBJ_UNAVAILABLE) {
|
||||
/* No messages available */
|
||||
return(MEMSCOPE_NO_MSG);
|
||||
}
|
||||
else {
|
||||
logMsg("error in MemScopeMsgGet\n");
|
||||
return(MEMSCOPE_ERROR);
|
||||
}
|
||||
}
|
||||
ptr = ptr + MemScope.msgLen;
|
||||
}
|
||||
/*
|
||||
if (numMsg > 0 ) {
|
||||
int buffLen;
|
||||
|
||||
logMsg("MsgGet...\t%i\n", numMsg);
|
||||
buffLen = 4 + (numMsg * MemScope.msgLen);
|
||||
for (i = 0; i < 20; i++) {
|
||||
logMsg("\tbyte %i:\t0x%02x\n", i, MemScope.wtxRecvBuff[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
//logMsg("Returned.\n");
|
||||
return numMsg;
|
||||
}
|
||||
|
||||
int MemLinkWtxPoolsGet(void)
|
||||
{
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
|
||||
int i;
|
||||
UINT blockCount = 0;
|
||||
UINT bufferedBlocks = 0;
|
||||
|
||||
|
||||
HeapBlockEntry * bufferTop = (HeapBlockEntry *)MemScope.wtxRecvBuff;
|
||||
|
||||
if (HeapFindPoolsCapable() == RTI_FALSE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
taskLock();
|
||||
|
||||
if (MemLinkHeapDataValid != RTI_TRUE) {
|
||||
|
||||
HeapFindPools(0, 0);
|
||||
wtxMemLinkHeap.poolCount = HeapCountPools();
|
||||
wtxMemLinkHeap.pools = HeapGetPools();
|
||||
wtxMemLinkHeap.currentPool = 0;
|
||||
wtxMemLinkHeap.currentBlock = 0;
|
||||
|
||||
MemLinkHeapDataValid = RTI_TRUE;
|
||||
//printf("Found %i pools.\n", wtxMemLinkHeap.poolCount);
|
||||
}
|
||||
|
||||
/* iterate over all memory pools we haven't finished */
|
||||
for (i = wtxMemLinkHeap.currentPool; i < wtxMemLinkHeap.poolCount; i++) {
|
||||
//printf("\tin pool %i\n", i);
|
||||
blockCount = HeapGetPoolBlocks(bufferTop,
|
||||
wtxMemLinkHeap.pools[i].poolTop,
|
||||
wtxMemLinkHeap.currentBlock,
|
||||
MEMLINK_MAX_BLOCKS - bufferedBlocks,
|
||||
RTI_TRUE);
|
||||
/*
|
||||
printf("\tfilled buffer with %i blocks\n", blockCount);
|
||||
printf("\t0x%08x\t0x%08x\t0x%08x\n",
|
||||
bufferTop[0].blockStart,
|
||||
bufferTop[0].blockSize,
|
||||
bufferTop[0].inUse);
|
||||
*/
|
||||
if (blockCount == MEMLINK_MAX_BLOCKS) {
|
||||
wtxMemLinkHeap.currentBlock += blockCount;
|
||||
return blockCount;
|
||||
} else if (blockCount < MEMLINK_MAX_BLOCKS) {
|
||||
wtxMemLinkHeap.currentBlock = 0;
|
||||
wtxMemLinkHeap.currentPool++;
|
||||
bufferedBlocks += blockCount;
|
||||
bufferTop += blockCount;
|
||||
} else {
|
||||
logMsg("LOGIC ERROR.\n");
|
||||
}
|
||||
}
|
||||
|
||||
taskUnlock();
|
||||
//printf("Unlocked and done...\n");
|
||||
if (bufferedBlocks == 0) {
|
||||
MemLinkHeapDataValid = RTI_FALSE;
|
||||
}
|
||||
return bufferedBlocks;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
RTIBool MemLinkWtxPatchInstall(MemLinkAllocData *linkAllocData,
|
||||
MemLinkFreeData *linkFreeData)
|
||||
{
|
||||
#if MEMSCOPE_NO_PATCHING
|
||||
dprintf("Patching target with heap patch method [wtx mode]\n");
|
||||
return MemScopeOldStart();
|
||||
#else
|
||||
MemScopeAllocData scopeAllocData;
|
||||
MemScopeFreeData scopeFreeData;
|
||||
|
||||
scopeAllocData.address = linkAllocData->address;
|
||||
scopeAllocData.paramNumPartId = linkAllocData->paramNumPartId;
|
||||
scopeAllocData.paramNumIdentifier = linkAllocData->paramNumIdentifier;
|
||||
scopeAllocData.paramNumAmount = linkAllocData->paramNumAmount;
|
||||
|
||||
scopeFreeData.address = linkFreeData->address;
|
||||
scopeFreeData.paramNumPartId = linkFreeData->paramNumPartId;
|
||||
scopeFreeData.paramNumIdentifier = linkFreeData->paramNumIdentifier;
|
||||
|
||||
dprintf("WtxPatchInstall: alloc @ %p / free @ %p\n",
|
||||
scopeAllocData.address, scopeFreeData.address);
|
||||
|
||||
if (RtiTools_ParamSignatureCreate(linkAllocData->paramString,
|
||||
&scopeAllocData.signature) == RTI_FALSE)
|
||||
{
|
||||
dprintf("Could not create signature from '%s'\n", linkAllocData->paramString);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
if (RtiTools_ParamSignatureCreate(linkFreeData->paramString,
|
||||
&scopeFreeData.signature) == RTI_FALSE)
|
||||
{
|
||||
dprintf("Could not create signature from '%s'\n", linkFreeData->paramString);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* Should be done -- now make the patch */
|
||||
if (MemScopePartStart(&scopeAllocData, &scopeFreeData) == RTI_FALSE) {
|
||||
dprintf("MemLinkPatchInstall: MemScopePartStart failed!\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
#endif /* if MEMSCOPE_NO_PATCHING */
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* wtxcalls.pkg.h - built from: wtxcalls.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef wtxcalls_pkg_h
|
||||
#define wtxcalls_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define MEMSCOPE_BATCH_SIZE (30)
|
||||
#define MAX_BATCH_MEMSCOPE_MSG_LEN (MEMSCOPE_BATCH_SIZE * MAX_MEMSCOPE_MSG_LEN + 4)
|
||||
|
||||
|
||||
#define MEMSCOPE_ERROR (-2)
|
||||
#define MEMSCOPE_NO_MSG (-1)
|
||||
#define MEMSCOPE_MORE_MSG (2)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* wtxcalls_pkg_h */
|
||||
@@ -0,0 +1,34 @@
|
||||
# Makefile - makefile for building ProfileScope
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building ProfileScope
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR = $(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ..
|
||||
|
||||
DOC_FILES =
|
||||
|
||||
LIB_BASE_NAME =
|
||||
|
||||
SUBDIRS = profileapi targetAgent
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
DKMS = $(LIB_ROOT)/$(DKMDIRBASE)/profile.so
|
||||
PROFILE_OBJS = $(LIB_ROOT)/$(LIBDIRBASE)/objprofile/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objclock/*.o \
|
||||
$(LIB_ROOT)/$(LIBDIRBASE)/objscopeutils/msgq.o
|
||||
|
||||
.PHONY: dkms
|
||||
|
||||
dkms: $(DKMS)
|
||||
|
||||
$(LIB_ROOT)/$(DKMDIRBASE)/profile.so: $(PROFILE_OBJS)
|
||||
$(LD_PARTIAL) $^ -o $@
|
||||
|
||||
LOCAL_CLEAN += $(DKMS)
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef RTI_LIST_H
|
||||
#define RTI_LIST_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef RTI_WIN32
|
||||
#define inline __inline
|
||||
#else
|
||||
#define inline __inline__
|
||||
#endif
|
||||
|
||||
typedef struct RTI_list_head {
|
||||
struct RTI_list_head *prev;
|
||||
struct RTI_list_head *next;
|
||||
} RTI_list_head;
|
||||
|
||||
/******************************
|
||||
* List operations
|
||||
*/
|
||||
#define RTI_INIT_LIST_HEAD(_h) do {\
|
||||
(_h)->next = (_h);\
|
||||
(_h)->prev = (_h);\
|
||||
} while (0);
|
||||
|
||||
#define RTI_list_for_each_safe(pos, n, head)\
|
||||
for (pos = (head)->next, n = pos->next; pos != (head);\
|
||||
pos = n, n = pos->next)
|
||||
|
||||
#define RTI_list_for_each RTI_list_for_each_safe
|
||||
|
||||
#define RTI_list_entry(_ptr,_type,_member)\
|
||||
((_type *)((char *)(_ptr)-(unsigned long)(&((_type *)0)->_member)))
|
||||
|
||||
static inline void RTI_list_del(RTI_list_head *n)
|
||||
{
|
||||
RTI_list_head *prev = n->prev;
|
||||
RTI_list_head *next = n->next;
|
||||
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
n->next = n->prev = (RTI_list_head*)0;
|
||||
}
|
||||
|
||||
static inline void RTI_list_add(RTI_list_head *newp,
|
||||
RTI_list_head *head)
|
||||
{
|
||||
struct RTI_list_head *n = head->next;
|
||||
|
||||
newp->prev = head;
|
||||
newp->next = n;
|
||||
head->next = newp;
|
||||
n->prev = newp;
|
||||
}
|
||||
|
||||
static inline void RTI_list_add_tail(RTI_list_head *newp,
|
||||
RTI_list_head *head)
|
||||
{
|
||||
struct RTI_list_head *p = head->prev;
|
||||
|
||||
newp->prev = p;
|
||||
newp->next = head;
|
||||
p->next = newp;
|
||||
head->prev = newp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/* profile_vx.h - built from: profileapi.c, /view/ot.40_RCPL8.2024030303/vobs/rtca/component_roots/comp_rtca/target/src/profile/profileapi/vx/profile.c
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef profile_vx_h
|
||||
#define profile_vx_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
# undef SMP_CONFIG
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define PROFILE_MAX_STACK_DEPTH (64)
|
||||
|
||||
typedef enum
|
||||
{ IGNORE_TID = 1,
|
||||
IGNORE_UID,
|
||||
IGNORE_CPU
|
||||
} ignoreType;
|
||||
|
||||
typedef enum {
|
||||
IDLE_THREAD = 1,
|
||||
KERNEL_THREAD,
|
||||
USER_THREAD,
|
||||
KERNEL_INTERRUPT,
|
||||
KERNEL_EXCEPTION,
|
||||
KERNEL_STATE
|
||||
} ProfileEntity;
|
||||
|
||||
|
||||
|
||||
typedef struct ProfileInfoStorage* ProfileInfo;
|
||||
|
||||
extern int ProfileDebuggingOutput;
|
||||
|
||||
|
||||
/**
|
||||
* ProfileFreeze - freeze (halt) or resume sampling
|
||||
*
|
||||
* This routine sets a Boolean flag controling sampling to the specified value
|
||||
* which either enables sampling (sample = RTI_TRUE) or disables sampling
|
||||
* (sample = RTI_FALSE).
|
||||
*
|
||||
* RETURN
|
||||
* RTI_TRUE - operation successful
|
||||
* RTI_FALSE - wrong tool
|
||||
*/
|
||||
extern RTIBool ProfileFreeze (RTIBool sample, ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileClear (ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileSetMode (
|
||||
unsigned int * tids, /* task/thread ID list */
|
||||
int size, /* number of IDs in list */
|
||||
RTIBool irqSampling, /* IRQ sampling allowed? */
|
||||
RTIBool dontClear, /* clear profile info after setting mode? */
|
||||
ProfileInfo pi,
|
||||
const void * xmlEngine);
|
||||
|
||||
|
||||
extern int ProfileSetSampleRate (int requestedSR, ProfileInfo pi,
|
||||
const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileKill (ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileConnectClk (char* clock, ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileCleanup (void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileSetIgnore (unsigned int* array, int size, ignoreType type,
|
||||
ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern int ProfileMsgsReceive (void *buffer, unsigned int bufsize);
|
||||
|
||||
|
||||
extern int ProfileGetStatus (void *buffer, unsigned int bufsize, ProfileInfo pi,
|
||||
const void* xmlEngine);
|
||||
|
||||
|
||||
extern ProfileInfo ProfileInit (char* clock, unsigned int* tids, int tidListSize,
|
||||
RTIBool irqSampling, int sampleRate, int maxSamples,
|
||||
int maxStack, const void* xmlEngine);
|
||||
|
||||
|
||||
|
||||
/* profilescope message format */
|
||||
typedef struct {
|
||||
ProfileEntity pentity; /* thread entity being profiled */
|
||||
int tid; /* thread id */
|
||||
int pid; /* process group id */
|
||||
int cpuid; /* cpu id */
|
||||
int numSamples; /* number of profile stack samples */
|
||||
void * stack[PROFILE_MAX_STACK_DEPTH]; /* stack samples */
|
||||
/* int sampleWeight; /@ #ticks between ISR and sample*/
|
||||
} ProfileMsgStorage, *ProfileMsg;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* profile_vx_h */
|
||||
@@ -0,0 +1,40 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../..
|
||||
|
||||
vpath %.c $(CURDIR)/vx
|
||||
LIB_BASE_NAME = profile
|
||||
|
||||
EXTRA_DEFINE += -DSCOPEPROFILEVERSION=\"4.11a\"
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include/vx \
|
||||
-I$(COMP_STACKTRACE_PATH)/include \
|
||||
-Ivx
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= profileapi.o profilesample.o profile.o
|
||||
|
||||
PKG_H = profileapi.pkg.h profilesample.pkg.h profile.pkg.h
|
||||
|
||||
HDR_PATH = ../include
|
||||
HEADERS = $(HDR_PATH)/profile_vx.h
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
|
||||
# Public header generation (needs to occur after inclusion of rules.library,
|
||||
# otherwise it hides the default build rule).
|
||||
|
||||
$(HDR_PATH)/profile_vx.h : profileapi.c profile.c
|
||||
$(MAKEHEADER) -C $(MAKEHEADERPUBKEYS) -o $@ $^
|
||||
@@ -0,0 +1,685 @@
|
||||
/* profile.pkg.h - built from: /view/ot.40_RCPL8.2024030303/vobs/rtca/component_roots/comp_rtca/target/src/profile/profileapi/vx/profile.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef profile_pkg_h
|
||||
#define profile_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* profilescope message format */
|
||||
typedef struct {
|
||||
ProfileEntity pentity; /* thread entity being profiled */
|
||||
int tid; /* thread id */
|
||||
int pid; /* process group id */
|
||||
int cpuid; /* cpu id */
|
||||
int numSamples; /* number of profile stack samples */
|
||||
void * stack[PROFILE_MAX_STACK_DEPTH]; /* stack samples */
|
||||
/* int sampleWeight; /@ #ticks between ISR and sample*/
|
||||
} ProfileMsgStorage, *ProfileMsg;
|
||||
|
||||
|
||||
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <regs.h>
|
||||
#include <intLib.h>
|
||||
#include <semLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <usrConfig.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <private/kernelBaseLibP.h>
|
||||
#include <private/kernelLibP.h>
|
||||
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#include <rtilib/rti_types.h>
|
||||
#ifdef SMP_CONFIG
|
||||
# include <rtilib/stSpinLock.h>
|
||||
# include <cpuset.h>
|
||||
# include <vxCpuLib.h>
|
||||
# include <private/taskToolsUtilLibP.h>
|
||||
# define KERNEL_ID kernelIdGet()
|
||||
#else
|
||||
# define KERNEL_ID kernelId
|
||||
#endif
|
||||
|
||||
|
||||
/* Globals */
|
||||
struct OSProfileInfoStorage {
|
||||
WIND_TCB * activeThread; /* Thread to sample */
|
||||
unsigned long sysMemTop; /* cached value of sysMemTop() */
|
||||
int samplerTid; /* tid of sampler task */
|
||||
|
||||
RTIBool irqSampling; /* whether sampling in interrupt or not */
|
||||
SEM_ID sem; /* synchronization semaphore for sampler */
|
||||
unsigned int spinTicks; /* ISR missed tick# when task selected */
|
||||
#ifdef SMP_CONFIG
|
||||
st_rwLock taskRWLock; /* private R/W spinlock for SMP systems */
|
||||
st_preemptLock preemptLock; /* private preemption lock */
|
||||
atomic_t cpuCurrent; /* CPU# currently being profiled */
|
||||
atomic_t cpuNext; /* next CPU# to be profiled */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef SMP_CONFIG
|
||||
static int lockKey = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/* Defines */
|
||||
|
||||
/* Please don't remove put any spaces before the \, it breaks GCC < 3 */
|
||||
#define v0printf(fmt, ...) printf("pid=0x%x, %s(%d): " fmt, taskIdSelf(),\
|
||||
__FUNCTION__, __LINE__, ## __VA_ARGS__)
|
||||
|
||||
/** **/
|
||||
/** OS-specific implementation functions **/
|
||||
/** **/
|
||||
|
||||
/* memory allocation/de-allocation defines (OS-specific) */
|
||||
#define malloc_KERNEL(size) malloc(size)
|
||||
#define free_KERNEL(pointer) free(pointer)
|
||||
|
||||
#define strlen_KERNEL(str) strlen(str)
|
||||
|
||||
/* memory management routine defines (OS-specific) */
|
||||
#define memcpy_KERNEL(dest, src, size) bcopy((const char*) src, (char *) dest,\
|
||||
size)
|
||||
|
||||
/* OS-specific defines to transfer data from kernel domain to profileagent */
|
||||
#define copy_to_agent(dest, src, size) bcopy((const char*) src, (char*) dest,\
|
||||
size)
|
||||
|
||||
#define PROFILE_KERNEL_TID ((WIND_TCB *) -2)
|
||||
#define PROFILE_IDLE_TID ((WIND_TCB *) -3)
|
||||
|
||||
#define OSGetCurrentRegs(opi) ((REG_SET *) &(opi->activeThread->regs))
|
||||
#define OSGetCurrentTid(opi) ((int) opi->activeThread)
|
||||
#define OSGetCurrentTask(opi) OSGetCurrentTid(opi)
|
||||
#define OSGetCurrentEuid(opi) (0)
|
||||
/* #define OSIsAddrInKernel(addr, opi) (addr < (opi->sysMemTop)) */
|
||||
#define OSIsAddrInKernel(addr, opi) (RTI_FALSE)
|
||||
#define OSGetIrqPolicy() IRQ_ROUND_ROBIN
|
||||
|
||||
/** **/
|
||||
/** Unused OS-specific implementation functions **/
|
||||
/** **/
|
||||
|
||||
#define OSContextSwitch(x,y)
|
||||
#define OSThreadListLock()
|
||||
#define OSThreadListUnlock()
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptLock - lock task against preemption
|
||||
*
|
||||
* This routine locks the current task/thread against preemption by locking
|
||||
* out scheduling on the CPU of the task of interest. Scheduling on other
|
||||
* CPUs is unaffected.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptLock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
task_lock (&opi->preemptLock);
|
||||
/* no blocking calls after this point! */
|
||||
#else
|
||||
if (opi->irqSampling == RTI_TRUE) {
|
||||
lockKey = intLock();
|
||||
} else {
|
||||
taskLock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptUnlock - unlock task from preemption
|
||||
*
|
||||
* This routine unlocks the current task/thread from preemption.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptUnlock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
task_unlock (&opi->preemptLock);
|
||||
#else
|
||||
if (opi->irqSampling == RTI_TRUE) {
|
||||
intUnlock(lockKey);
|
||||
} else {
|
||||
taskUnlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptReadLock - lock task against writer preemption
|
||||
*
|
||||
* This routine locks the current task/thread against preemption by writers
|
||||
* by locking out scheduling on the CPU of the calling task and entering a
|
||||
* spin loop until read permission is granted. Scheduling on other CPUs is
|
||||
* unaffected.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptReadLock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskRDlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptLock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptReadUnlock - unlock task from writer preemption
|
||||
*
|
||||
* This routine unlocks the current task/thread from writer preemption.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptReadUnlock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskRDunlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptUnlock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptWriteLock - lock task against reader/writer preemption
|
||||
*
|
||||
* This routine locks the current task/thread against preemption by readers
|
||||
* and any other writer by locking out scheduling on the CPU of the calling
|
||||
* task and entering a spin loop until write permission is granted.
|
||||
* Scheduling on other CPUs is unaffected.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptWriteLock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskWRlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptLock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptWriteUnlock - unlock task from reader/writer preemption
|
||||
*
|
||||
* This routine unlocks the current task/thread from reader/writer preemption.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptWriteUnlock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskWRunlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptUnlock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetNumCPUs - get number of CPUs in system
|
||||
*
|
||||
* This routine returns the configured number of CPUs in the system.
|
||||
* NOTE: this number may not reflect the actual number of CPUs enabled!
|
||||
*
|
||||
* RETURNS: number of CPUs configured
|
||||
*/
|
||||
|
||||
static inline int OSGetNumCPUs (void)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
return (vxCpuConfiguredGet());
|
||||
#else
|
||||
return (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetCurrentPC - get the current task's PC
|
||||
*
|
||||
* This routine returns the current task/thread PC value.
|
||||
*
|
||||
* RETURNS: current thread/task PC value or 0xffffffff for untraced tasks
|
||||
*/
|
||||
|
||||
static inline unsigned long OSGetCurrentPC (OSProfileInfo opi)
|
||||
{
|
||||
if ((opi->activeThread == PROFILE_IDLE_TID) ||
|
||||
(opi->activeThread == PROFILE_KERNEL_TID))
|
||||
{
|
||||
return (0xffffffff);
|
||||
} else {
|
||||
return ((unsigned long) opi->activeThread->regs.reg_pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetCurrentCPU - get current CPU#
|
||||
*
|
||||
* This routine returns the index of the CPU on which the caller is running.
|
||||
*
|
||||
* CAVEAT: there is no guarantee that the CPU will not change prior to it's
|
||||
* return! It is the responsibility of the caller to ensure that scheduling
|
||||
* is suspended prior to calling this routine to ensure the returned index
|
||||
* is valid.
|
||||
*
|
||||
* INTERNAL
|
||||
* - ProfileScope supports profiling one CPU at a time on VxWorks.
|
||||
*
|
||||
* RETURNS: 0 to N-1, where N is the configured number of CPUs in the system.
|
||||
*/
|
||||
|
||||
static inline int OSGetCurrentCPU (void)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
return (vxCpuIndexGet());
|
||||
#else
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetSamplerTid - get task ID of task selected for sampling
|
||||
*
|
||||
* This routine returns the task ID of the task to be sampled.
|
||||
*
|
||||
* RETURNS: task ID of task to be sampled
|
||||
*/
|
||||
|
||||
static inline int OSGetSamplerTid (OSProfileInfo opi)
|
||||
{
|
||||
return (opi->samplerTid);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SMP_CONFIG
|
||||
|
||||
/**
|
||||
* localCpuTaskStateGet - get state of current task on local CPU
|
||||
*
|
||||
* Returns state of interrupted task on local CPU.
|
||||
*
|
||||
* RETURNS
|
||||
* TASK_LIB_CPU_HOLDS_SPINLOCK - task has a spin lock
|
||||
* TASK_LIB_CPU_HOLDS_KERNEL_LOCK - task has entered kernel and locked it
|
||||
* TASK_LIB_CPU_NO_INFO - task not in special state
|
||||
*
|
||||
* INTERNAL
|
||||
* This is a code segment taken directly from taskInfoByCpuGet().
|
||||
*/
|
||||
static __inline__
|
||||
int localCpuTaskStateGet (int cpuNum)
|
||||
{
|
||||
/*
|
||||
* It is never possible for a CPU to hold both a spinlock and the kernel
|
||||
* lock. This information could be changed out from under the caller, so
|
||||
* this has intentionally made an 'if, else if' block to avoid the
|
||||
* possibility of both TASK_LIB_CPU_HOLDS_SPINLOCK and
|
||||
* TASK_LIB_CPU_HOLDS_KERNEL_LOCK from being set.
|
||||
*/
|
||||
|
||||
if ((_WRS_KERNEL_CPU_GLOBAL_GET(cpuNum, spinLockIsrCnt) != 0) ||
|
||||
(_WRS_KERNEL_CPU_GLOBAL_GET(cpuNum, spinLockTaskCnt) != 0))
|
||||
{
|
||||
/* the CPU holds a spinlock, mark return value as such */
|
||||
|
||||
return TASK_LIB_CPU_HOLDS_SPINLOCK;
|
||||
}
|
||||
else if (KERNEL_LOCK_OWNER_GET() == cpuNum)
|
||||
{
|
||||
/* the CPU holds the kernel lock, mark return value as such */
|
||||
|
||||
return TASK_LIB_CPU_HOLDS_KERNEL_LOCK;
|
||||
}
|
||||
|
||||
return TASK_LIB_CPU_NO_INFO;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSCreateContext - record current context (TCB)
|
||||
*
|
||||
* This routine records the TCB ID and state of the current task/thread.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline RTIBool OSCreateContext (OSProfileInfo opi,
|
||||
unsigned int missedTicks)
|
||||
{
|
||||
int tid = taskIdSelf(); /* default task ID */
|
||||
#ifdef SMP_CONFIG
|
||||
atomic_t cpuIndex = vxCpuIndexGet();
|
||||
WIND_TCB * tcb = NULL;
|
||||
int stateInfo = localCpuTaskStateGet(cpuIndex);
|
||||
STATUS result = OK;
|
||||
unsigned int maxCpu = vxCpuConfiguredGet();
|
||||
|
||||
/* don't query our own CPU; we already know what task was running on it */
|
||||
if (opi->cpuNext != cpuIndex) {
|
||||
result = taskInfoByCpuGet (opi->cpuNext, &tid, &stateInfo);
|
||||
}
|
||||
tcb = taskTcb (tid);
|
||||
|
||||
/* set next and current victim CPU indices */
|
||||
cpuIndex = opi->cpuNext + 1;
|
||||
if (cpuIndex >= maxCpu) cpuIndex = 0;
|
||||
vxAtomicSet (&opi->cpuCurrent, opi->cpuNext);
|
||||
vxAtomicSet (&opi->cpuNext, cpuIndex);
|
||||
|
||||
/* If bogus CPU or sampler task ID, just return */
|
||||
if ((result == ERROR) || (OSGetSamplerTid (opi) == tid)) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* If idle task encountered, don't trace it, just record it.
|
||||
* Only a system idle task can have priority 287.
|
||||
*/
|
||||
if ((tid == 0) || (tcb == NULL) || (tcb->priority == 287)) {
|
||||
opi->activeThread = PROFILE_IDLE_TID;
|
||||
}
|
||||
|
||||
/* If kernel state task, don't trace it,
|
||||
* just record it and allow task to continue.
|
||||
*/
|
||||
else if ((stateInfo == TASK_LIB_CPU_HOLDS_KERNEL_LOCK) ||
|
||||
(KERNEL_ENTERED_ME()))
|
||||
{
|
||||
opi->activeThread = PROFILE_KERNEL_TID;
|
||||
}
|
||||
|
||||
/* If task holds a spinlock, we trace it immediately
|
||||
* after it releases the lock and continues.
|
||||
* TD: Add support for weighting sample by time spent in spinlock!
|
||||
* Add SPIN_LOCK entity?
|
||||
* else {
|
||||
* if (stateInfo == TASK_LIB_CPU_HOLDS_SPINLOCK) {
|
||||
* opi->pentity = SPIN_LOCK;
|
||||
* }
|
||||
* opi->activeThread = tcb;
|
||||
* ...
|
||||
*/
|
||||
|
||||
/* Set ID of task to sample and start tick timer
|
||||
* to record any time spent in a spinlock.
|
||||
*/
|
||||
else {
|
||||
opi->activeThread = tcb;
|
||||
opi->spinTicks = missedTicks;
|
||||
}
|
||||
#else
|
||||
if (kernelIsIdle) {
|
||||
opi->activeThread = PROFILE_IDLE_TID;
|
||||
} else if (kernelState || (taskIdCurrent == NULL)) {
|
||||
opi->activeThread = PROFILE_KERNEL_TID;
|
||||
} else if (OSGetSamplerTid (opi) != tid) {
|
||||
opi->activeThread = taskIdCurrent;
|
||||
opi->spinTicks = missedTicks;
|
||||
} else {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSRunSamplerThread - trigger execution of the sampler task
|
||||
*
|
||||
* This routine triggers execution of the sampler task.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSRunSamplerThread (OSProfileInfo opi)
|
||||
{
|
||||
(void)semGive(opi->sem);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSWaitSamplerThread - wait for trigger to start sampling
|
||||
*
|
||||
* This routine waits for the trigger to start the sampler task.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSWaitSamplerThread (OSProfileInfo opi)
|
||||
{
|
||||
(void)semTake(opi->sem, WAIT_FOREVER);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSFindThread - determine if thread/task to be sampled was found
|
||||
*
|
||||
* This routine determines if a task/thread was found for the sampler task.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if task found, else, RTI_FALSE
|
||||
*/
|
||||
|
||||
static inline RTIBool OSFindThread (int tid, OSProfileInfo opi)
|
||||
{
|
||||
if (tid == opi->samplerTid) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
opi->activeThread = taskTcb(tid);
|
||||
|
||||
if (opi->activeThread == NULL) {
|
||||
return (RTI_FALSE);
|
||||
} else {
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPopulateMsgStruct - populate profile message structure by task type
|
||||
*
|
||||
* This routine populates the message structure to be sent to the host and
|
||||
* returns a boolean indicating whether the task was a special case or not.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if idle or kernel task, else, RTI_FALSE
|
||||
*/
|
||||
|
||||
static inline RTIBool OSPopulateMsgStruct (OSProfileInfo opi, ProfileMsg msg,
|
||||
RTIBool systemMode)
|
||||
{
|
||||
RTIBool ret = RTI_FALSE;
|
||||
|
||||
/* if kernel is running idle */
|
||||
if (opi->activeThread == PROFILE_IDLE_TID) {
|
||||
msg->pentity = IDLE_THREAD;
|
||||
msg->pid = (int) KERNEL_ID;
|
||||
msg->numSamples = 0;
|
||||
ret = RTI_TRUE;
|
||||
} else if (opi->activeThread == PROFILE_KERNEL_TID) {
|
||||
msg->pentity = KERNEL_STATE;
|
||||
msg->pid = (int) KERNEL_ID;
|
||||
msg->numSamples = 0;
|
||||
ret = RTI_TRUE;
|
||||
} else {
|
||||
if (RTP_ID_OF_TASK(opi->activeThread) == KERNEL_ID) {
|
||||
msg->pentity = KERNEL_THREAD;
|
||||
} else {
|
||||
/* for now, if we come across an RTP thread, we dont
|
||||
context trace that thread. */
|
||||
msg->pentity = USER_THREAD;
|
||||
}
|
||||
msg->pid = (int) RTP_ID_OF_TASK(opi->activeThread);
|
||||
}
|
||||
msg->tid = (int) opi->activeThread;
|
||||
#ifdef SMP_CONFIG
|
||||
msg->cpuid = opi->cpuCurrent;
|
||||
#else
|
||||
msg->cpuid = 0;
|
||||
#endif
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSThreadExists - validate task existence
|
||||
*
|
||||
* This routine validates the task ID of the task to be sampled.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if valid task ID, else, RTI_FALSE
|
||||
*/
|
||||
|
||||
extern RTIBool OSThreadExists (int tid);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileSetMode - set sampling mode
|
||||
*
|
||||
* This routine sets the sampling mode (IRQ or not) and starts the sampler
|
||||
* task if IRQs are not to be sampled. If IRQs are to be sampled and a
|
||||
* sampler task is already running, the sampler task is deleted. (Sampling
|
||||
* is not done by a sampler task when sampling IRQ state.)
|
||||
*
|
||||
* RETURNS: RTI_TRUE if mode set, else, RTI_FALSE if sampler task spawn failed
|
||||
*/
|
||||
|
||||
extern RTIBool OSProfileSetMode (void* data, RTIBool irqSampling, OSProfileInfo opi);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileKill - done profiling, kill tool
|
||||
*
|
||||
* This routine kills the sampler task and cleans up prior to exiting.
|
||||
*
|
||||
* RETURNS: RTI_TRUE on success
|
||||
*/
|
||||
|
||||
extern RTIBool OSProfileKill (OSProfileInfo opi);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileConnectClk - connect profiler to a clock
|
||||
*
|
||||
* This routine connects the profiler to a system clock tick interrupt handler
|
||||
* list. Either an auxilliary clock, if available, or the system clock is used.
|
||||
*
|
||||
* RETURNS: RTI_TRUE (OK) if connected, else, RTI_FALSE (ERROR) if connect
|
||||
* failed
|
||||
*/
|
||||
|
||||
extern RTIBool OSProfileConnectClk (void* data, char* clock);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileSetSampleRate - set sampler clock frequency of aux clock
|
||||
*
|
||||
* This routine attempts to set the frequency of the auxilliary clock if it
|
||||
* is used for sampling. The actual frequency set is returned, for either
|
||||
* the auxilliary or system clock, which ever is used for sampling.
|
||||
*
|
||||
* RETURNS: actual sampler clock frequency
|
||||
*/
|
||||
|
||||
extern int OSProfileSetSampleRate (int requestedSR, char* clock);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileInit - initialize the profiler
|
||||
*
|
||||
* This routine initializes the profiler.
|
||||
*
|
||||
* INTERNAL: currently this routine just allocates a profiler structure
|
||||
* instance.
|
||||
*
|
||||
* RETURNS: the OSProfileInfoStorage structure pointer or NULL on failure
|
||||
*/
|
||||
|
||||
extern OSProfileInfo OSProfileInit (RTIBool irqSampling);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProcessSamples - process profiler samples
|
||||
*
|
||||
* This routine is not required for VxWorks.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
extern void OSProcessSamples (void* buffer, int size, OSProfileInfo opi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* profile_pkg_h */
|
||||
@@ -0,0 +1,909 @@
|
||||
/* profileapi.c - ProfileScope interface code. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2009, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,10oct13,wzc Fix prevent warnings.
|
||||
01c,29jun12,wzc WIND00350881 - check malloc return value.
|
||||
01c,30nov11,wzc WIND00314125 - Fix the sample rate for system clock.
|
||||
01b,26oct09,pca Fixed subsampling rate calculation, for defect 179850
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
34a,01jul09,wzc Fix coverity prevent errors FORWARD NULL in line 664
|
||||
34a,27aug08,mas added vsbConfig.h; changed _WRS_XV_SMP to _WRS_CONFIG_SMP
|
||||
33a,30jan07,mas made SMP-compliant
|
||||
20a,28oct04,avd Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
ProfileScope interface code.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
# include <rtilib/vxVersions.h>
|
||||
# include <vxWorks.h>
|
||||
# include <logLib.h>
|
||||
# if VXWORKS_VERSION_6_6_OR_BETTER
|
||||
# include <vxAtomicLib.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#pragma begin_Package
|
||||
#include <rtitools/rtitools_msgq.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#pragma end_Package
|
||||
|
||||
#include <rtitools/rtitools_clock.h>
|
||||
|
||||
/*
|
||||
* Public declarations (common to VxWorks and Linux)
|
||||
*/
|
||||
|
||||
#pragma begin_Public
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
# undef SMP_CONFIG
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define PROFILE_MAX_STACK_DEPTH (64)
|
||||
|
||||
typedef enum
|
||||
{ IGNORE_TID = 1,
|
||||
IGNORE_UID,
|
||||
IGNORE_CPU
|
||||
} ignoreType;
|
||||
|
||||
typedef enum {
|
||||
IDLE_THREAD = 1,
|
||||
KERNEL_THREAD,
|
||||
USER_THREAD,
|
||||
KERNEL_INTERRUPT,
|
||||
KERNEL_EXCEPTION,
|
||||
KERNEL_STATE
|
||||
} ProfileEntity;
|
||||
|
||||
#pragma end_Public
|
||||
|
||||
|
||||
#pragma begin_Package
|
||||
|
||||
typedef enum {
|
||||
IRQ_ROUND_ROBIN = 1,
|
||||
IRQ_ALL_CPUS,
|
||||
IRQ_UNKNOWN
|
||||
} irqPolicy;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ticks;
|
||||
unsigned long* count;
|
||||
unsigned short on;
|
||||
} SoftTimer;
|
||||
|
||||
typedef struct {
|
||||
unsigned int* id;
|
||||
unsigned int size;
|
||||
} ignoreList;
|
||||
|
||||
struct OSProfileInfoStorage;
|
||||
typedef struct OSProfileInfoStorage* OSProfileInfo;
|
||||
|
||||
struct ProfileInfoStorage {
|
||||
OSProfileInfo opi; /* OS-specific data structure */
|
||||
|
||||
int * profileTidList; /* useful in single thread/process mode, to
|
||||
determine which thread/process to sample */
|
||||
int * acProfileTidList; /* At a given instance, this is a copy
|
||||
of profileTidList */
|
||||
int tidListSize;
|
||||
RTIBool tidListChanged; /* flag indicating that profileTidList has
|
||||
changed */
|
||||
|
||||
char* clock; /* clock string pointing to sample clock */
|
||||
SoftTimer timer; /* software timer to sub-sample from max clock
|
||||
(system/aux) frequency */
|
||||
|
||||
ignoreList ignoreCpus; /* list of currently ignored CPUs */
|
||||
ignoreList ignoreUids; /* list of currently ignored user ids */
|
||||
ignoreList ignoreTids; /* list of currently ignored thread ids */
|
||||
|
||||
RTIBool sampleFlag; /* to activate/de-activate sampling */
|
||||
RTIBool irqSampling; /* whether sampling in interrupt or not*/
|
||||
RTIBool takingSample; /* flag to know if we are missing interrupt */
|
||||
|
||||
int maxSamples; /* maximum samples to collect before overflow */
|
||||
int maxStack; /* <= 64 */
|
||||
int sampleRate;
|
||||
|
||||
/* error count */
|
||||
unsigned int contextErr; /* Increment when a context trace fails. */
|
||||
unsigned int bufferErr; /* Increment when samples buffer is full. */
|
||||
unsigned int depthErr; /* Increment if stack deeper than maxStack. */
|
||||
unsigned int fpMemErr; /* Increment if fp out of bounds. */
|
||||
unsigned int pcMemErr; /* Increment if pc out of bounds. */
|
||||
unsigned int interruptErr; /* Increment if new interrupt happens, when
|
||||
previous interrupt is being processed */
|
||||
unsigned int sampleErr; /* Increment if sampled context corresponds to
|
||||
context of sampler thread (can't context
|
||||
trace in such case) */
|
||||
|
||||
RTIMsgQHdrPtr msgQ; /* A message queue to store samples */
|
||||
};
|
||||
|
||||
#define v1printf if (ProfileDebuggingOutput >= 1) v0printf
|
||||
#define v2printf if (ProfileDebuggingOutput >= 2) v0printf
|
||||
#define v3printf if (ProfileDebuggingOutput >= 3) v0printf
|
||||
|
||||
#define PROFILE_MSG_HDR_SIZE ((int) &((ProfileMsgStorage *) 0)->stack)
|
||||
|
||||
#pragma end_Package
|
||||
|
||||
#pragma begin_Public
|
||||
typedef struct ProfileInfoStorage* ProfileInfo;
|
||||
#pragma end_Public
|
||||
|
||||
#include "profile.pkg.h"
|
||||
#include "profilesample.pkg.h"
|
||||
#include <rtilib/makeheader.h>
|
||||
|
||||
Public int ProfileDebuggingOutput = 0;
|
||||
|
||||
typedef struct ActivePIListTag {
|
||||
ProfileInfo pi;
|
||||
struct ActivePIListTag* next;
|
||||
} ActivePIList;
|
||||
|
||||
/* defines */
|
||||
#define PROFILE_INT_SCALE (1000)
|
||||
#define PROFILE_INT_SCALE_10th (100)
|
||||
|
||||
#if defined(RTI_LINUX) && defined(MODULE)
|
||||
# define strncpy ST_strncpy
|
||||
#endif
|
||||
|
||||
/* Global variables, common to all instances of ProfileInfo. */
|
||||
private ProfileInfo ProfileLastPI = 0; /* The last-accessed profile */
|
||||
private ActivePIList* activePI = 0; /* list of active profiles */
|
||||
|
||||
|
||||
/*
|
||||
* Private Functions
|
||||
*/
|
||||
|
||||
Private
|
||||
void ProfileAddPI (ProfileInfo pi)
|
||||
{
|
||||
ActivePIList *item, *tmp = activePI;
|
||||
|
||||
/* insert into the active ProfileInfo list */
|
||||
item = (ActivePIList*) malloc_KERNEL (sizeof(ActivePIList));
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
item->pi = pi;
|
||||
item->next = 0;
|
||||
|
||||
if (activePI == 0) {
|
||||
activePI = item;
|
||||
}
|
||||
else {
|
||||
while (tmp->next != NULL) { tmp = tmp->next; }
|
||||
tmp->next = item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void ProfileDeletePI (ProfileInfo pi)
|
||||
{
|
||||
ActivePIList *curr = activePI, *prev = activePI;
|
||||
|
||||
/* remove item the active ProfileInfo list */
|
||||
while (curr) {
|
||||
if (curr->pi != pi) {
|
||||
prev = curr;
|
||||
curr = curr->next;
|
||||
} else {
|
||||
if (curr == activePI)
|
||||
activePI = curr->next;
|
||||
else
|
||||
prev->next = curr->next;
|
||||
free_KERNEL (curr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
RTIBool ProfileCheckPI (ProfileInfo pi)
|
||||
{
|
||||
ActivePIList* tmp = activePI;
|
||||
|
||||
while(tmp) {
|
||||
if (tmp->pi == pi)
|
||||
return (RTI_TRUE);
|
||||
else
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
ProfileInfo ProfileGetLastPI (ProfileInfo pi, const char * const caller)
|
||||
{
|
||||
if (pi == 0) {
|
||||
pi = ProfileLastPI;
|
||||
} else {
|
||||
/* check if this is a valid profile */
|
||||
if (ProfileCheckPI (pi) == RTI_TRUE)
|
||||
ProfileLastPI = pi;
|
||||
else {
|
||||
pi = 0;
|
||||
v0printf ("No active profile (caller: %s)!\n", caller);
|
||||
}
|
||||
}
|
||||
return (pi);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Public Profile API Functions
|
||||
*/
|
||||
|
||||
|
||||
Public
|
||||
/**
|
||||
* ProfileFreeze - freeze (halt) or resume sampling
|
||||
*
|
||||
* This routine sets a Boolean flag controling sampling to the specified value
|
||||
* which either enables sampling (sample = RTI_TRUE) or disables sampling
|
||||
* (sample = RTI_FALSE).
|
||||
*
|
||||
* RETURN
|
||||
* RTI_TRUE - operation successful
|
||||
* RTI_FALSE - wrong tool
|
||||
*/
|
||||
RTIBool ProfileFreeze (RTIBool sample, ProfileInfo pi, const void* xmlEngine)
|
||||
{
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileFreeze")) == 0) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* allow only valid RTIBool values */
|
||||
if (sample != RTI_FALSE) sample = RTI_TRUE;
|
||||
|
||||
#if VXWORKS_VERSION_6_6_OR_BETTER
|
||||
vxAtomicSet (&pi->sampleFlag, sample); /* halt or resume sampling */
|
||||
#else
|
||||
/* acquire OS-specific pre-emption lock */
|
||||
OSPreemptLock (pi->opi);
|
||||
pi->sampleFlag = sample; /* halt or resume sampling */
|
||||
OSPreemptUnlock (pi->opi);
|
||||
#endif
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
RTIBool ProfileClear (ProfileInfo pi, const void* xmlEngine)
|
||||
{
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileClear")) == 0) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* halt sampling and wait until current sample, if any, is done */
|
||||
ProfileFreeze (RTI_FALSE, pi, xmlEngine);
|
||||
while (pi->takingSample == RTI_TRUE) { }
|
||||
|
||||
pi->contextErr = 0;
|
||||
pi->bufferErr = 0;
|
||||
pi->depthErr = 0;
|
||||
pi->fpMemErr = 0;
|
||||
pi->pcMemErr = 0;
|
||||
|
||||
RTIMsgQClear (pi->msgQ);
|
||||
|
||||
/* resume sampling */
|
||||
ProfileFreeze (RTI_TRUE, pi, xmlEngine);
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
RTIBool ProfileSetMode (
|
||||
unsigned int * tids, /* task/thread ID list */
|
||||
int size, /* number of IDs in list */
|
||||
RTIBool irqSampling, /* IRQ sampling allowed? */
|
||||
RTIBool dontClear, /* clear profile info after setting mode? */
|
||||
ProfileInfo pi,
|
||||
const void * xmlEngine)
|
||||
{
|
||||
int i;
|
||||
int * tmp1;
|
||||
int * tmp2;
|
||||
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileSetMode")) == 0) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* acquire OS-specific pre-emption lock while changing thread lists */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteLock(pi->opi); /* ===(P)=== */
|
||||
#else
|
||||
OSPreemptLock(pi->opi); /* ===(P)=== */
|
||||
#endif
|
||||
|
||||
if (size != pi->tidListSize) {
|
||||
tmp1 = (int*) malloc_KERNEL (size * sizeof(int));
|
||||
tmp2 = (int*) malloc_KERNEL (size * sizeof(int));
|
||||
|
||||
if (!tmp1 || !tmp2) {
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteUnlock(pi->opi); /* ===P=== */
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi); /* ===P=== */
|
||||
#endif
|
||||
free_KERNEL (tmp1);
|
||||
free_KERNEL (tmp2);
|
||||
return (RTI_FALSE);
|
||||
} else {
|
||||
free_KERNEL (pi->profileTidList);
|
||||
free_KERNEL (pi->acProfileTidList);
|
||||
pi->profileTidList = tmp1;
|
||||
pi->acProfileTidList = tmp2;
|
||||
pi->tidListSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the flag so that during next sampling instance, new
|
||||
* profileTidList will be copied to acProfileTidList.
|
||||
*/
|
||||
pi->tidListChanged = RTI_TRUE;
|
||||
|
||||
/* system mode profiling */
|
||||
if (tids[0] == ~0) {
|
||||
pi->profileTidList[0] = ~0;
|
||||
}
|
||||
|
||||
/* single thread/process mode */
|
||||
else {
|
||||
/* Lock the OS thread list to search the thread list for given tid */
|
||||
OSThreadListLock();
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
RTIBool threadExists = OSThreadExists(tids[i]);
|
||||
|
||||
if (threadExists != RTI_TRUE) {
|
||||
pi->profileTidList[0] = -1;
|
||||
pi->tidListSize = 1;
|
||||
|
||||
/* Unlock the OS thread list */
|
||||
OSThreadListUnlock();
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteUnlock(pi->opi); /* ===P=== */
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi); /* ===P=== */
|
||||
#endif
|
||||
v0printf ("bad thread id %d.\n", tids[i]);
|
||||
return (RTI_FALSE);
|
||||
} else {
|
||||
pi->profileTidList[i] = tids[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlock the OS thread list */
|
||||
OSThreadListUnlock();
|
||||
}
|
||||
|
||||
/* Change any OS-specific settings */
|
||||
OSProfileSetMode ((void*)pi, irqSampling, pi->opi);
|
||||
pi->irqSampling = irqSampling;
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteUnlock(pi->opi); /* ===P=== */
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi); /* ===P=== */
|
||||
#endif
|
||||
|
||||
if (!dontClear) {
|
||||
ProfileClear (pi, xmlEngine);
|
||||
}
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/**
|
||||
* Return the subsampling rate which creates an effective sampling rate as
|
||||
* close to the requested_rate as possible. This handles cases where the user
|
||||
* wants a frequency of 11Hz, but the clock only runs at 100Hz. In this case
|
||||
* we want to subsample at every 9 clock ticks giving us an effective sampling
|
||||
* rate of ~11.111Hz.
|
||||
*/
|
||||
unsigned int subsampling_rate_calculate(unsigned int requested_rate,
|
||||
unsigned int clock_frequency)
|
||||
{
|
||||
/* "lower" is the subsampling rate which will result in an effective rate
|
||||
less than or equal to the requested rate, whereas "upper" is the rate
|
||||
which results in an effective rate greater than or equal to the
|
||||
requested rate. */
|
||||
unsigned int lower, upper;
|
||||
|
||||
/* calculate upper and lower bounds to get the closest match */
|
||||
lower = clock_frequency / requested_rate;
|
||||
upper = lower + 1;
|
||||
|
||||
/* figure out whether lower or upper is closer to clockrate */
|
||||
if ((clock_frequency - (lower * requested_rate)) <
|
||||
((upper * requested_rate) - clock_frequency))
|
||||
{
|
||||
if (lower == 0) {
|
||||
/* this happens when the requested rate is faster than the clock
|
||||
frequency. The best we can do at this point is use the full
|
||||
clock speed (subsampling rate of 1). */
|
||||
return 1;
|
||||
}
|
||||
return lower;
|
||||
} else {
|
||||
return upper;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
int ProfileSetSampleRate (int requestedSR, ProfileInfo pi,
|
||||
const void* xmlEngine)
|
||||
{
|
||||
unsigned int clockrate, i;
|
||||
const unsigned int cpus = OSGetNumCPUs();
|
||||
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileSetSampleRate")) == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (requestedSR <= 0) {
|
||||
requestedSR = 113;
|
||||
}
|
||||
|
||||
clockrate = OSProfileSetSampleRate (requestedSR, pi->clock);
|
||||
|
||||
/*Setup fixed SYS_CLK sampleRate*/
|
||||
if (strcmp (pi->clock, SYS_CLK) == 0) {
|
||||
requestedSR = clockrate;
|
||||
}
|
||||
|
||||
/* if sampling is done on all cpus when triggered, scale up the effective
|
||||
clock frequency */
|
||||
if (OSGetIrqPolicy() == IRQ_ALL_CPUS) {
|
||||
clockrate *= cpus;
|
||||
}
|
||||
|
||||
pi->timer.ticks = subsampling_rate_calculate(requestedSR, clockrate);
|
||||
|
||||
/* acquire OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteLock(pi->opi); /* ===(P)=== */
|
||||
#else
|
||||
OSPreemptLock(pi->opi); /* ===(P)=== */
|
||||
#endif
|
||||
|
||||
for (i = 0; i < cpus; i++) {
|
||||
pi->timer.count[i] = pi->timer.ticks;
|
||||
}
|
||||
pi->timer.on = 1;
|
||||
pi->sampleRate = clockrate / pi->timer.ticks;
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteUnlock(pi->opi); /* ===P=== */
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi); /* ===P=== */
|
||||
#endif
|
||||
|
||||
if (((pi->sampleRate * PROFILE_INT_SCALE) / requestedSR >
|
||||
(11 * PROFILE_INT_SCALE_10th) ) ||
|
||||
((pi->sampleRate * PROFILE_INT_SCALE) / requestedSR <
|
||||
(9 * PROFILE_INT_SCALE_10th) ) )
|
||||
{
|
||||
v0printf ("Rate (%d Hz) not achievable, using %d Hz\n", requestedSR,
|
||||
pi->sampleRate);
|
||||
}
|
||||
|
||||
v1printf ("Set sample rate to %d (ticks: %lu).\n", pi->sampleRate,
|
||||
pi->timer.ticks);
|
||||
return (pi->sampleRate);
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
RTIBool ProfileKill (ProfileInfo pi, const void* xmlEngine)
|
||||
{
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileKill")) == 0) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
if (pi->clock) {
|
||||
RTIClkDisconnect (pi, pi->clock);
|
||||
free_KERNEL (pi->clock);
|
||||
pi->clock = 0;
|
||||
}
|
||||
|
||||
if (pi->timer.count != 0) {
|
||||
free_KERNEL (pi->timer.count);
|
||||
}
|
||||
if (pi->ignoreCpus.id != 0) {
|
||||
free_KERNEL (pi->ignoreCpus.id);
|
||||
}
|
||||
if (pi->ignoreUids.id != 0) {
|
||||
free_KERNEL (pi->ignoreUids.id);
|
||||
}
|
||||
if (pi->ignoreTids.id != 0) {
|
||||
free_KERNEL (pi->ignoreTids.id);
|
||||
}
|
||||
|
||||
/* important to delete mesg queue after disabling clock */
|
||||
RTIMsgQDelete (pi->msgQ);
|
||||
free_KERNEL (pi->profileTidList);
|
||||
free_KERNEL (pi->acProfileTidList);
|
||||
|
||||
OSProfileKill (pi->opi);
|
||||
|
||||
/* delete pi from active profiles list */
|
||||
ProfileDeletePI (pi);
|
||||
free_KERNEL (pi);
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
RTIBool ProfileConnectClk (char* clock, ProfileInfo pi, const void* xmlEngine)
|
||||
{
|
||||
#define CLOCK_NAME_LEN (256)
|
||||
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileConnectClk")) == 0) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* stop sampling for the duration of setting new sample rate */
|
||||
ProfileFreeze (RTI_FALSE, pi, xmlEngine);
|
||||
|
||||
if (pi->timer.count == 0) {
|
||||
pi->timer.count = (unsigned long*)
|
||||
malloc_KERNEL (sizeof(unsigned long) * OSGetNumCPUs());
|
||||
if (pi->timer.count == 0) {
|
||||
/* dont un-freeze, as sampler would crash if timer.count
|
||||
is NULL */
|
||||
v0printf ("Couldn't allocate count.\n");
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
}
|
||||
pi->timer.on = 0;
|
||||
|
||||
/* Setup relevant clock parameters */
|
||||
if (pi->clock) {
|
||||
RTIClkDisconnect (pi, pi->clock);
|
||||
free_KERNEL (pi->clock);
|
||||
}
|
||||
|
||||
// TD: should this block be replaced with a call to strdup()?
|
||||
pi->clock = malloc_KERNEL (sizeof(char) * CLOCK_NAME_LEN);
|
||||
if (!pi->clock) {
|
||||
v0printf ("Couldn't allocate clock.\n");
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
strncpy (pi->clock, clock, CLOCK_NAME_LEN);
|
||||
|
||||
if (OSProfileConnectClk ((void*)pi, pi->clock) == RTI_FALSE) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* set the sample rate first */
|
||||
ProfileSetSampleRate (pi->sampleRate, pi, xmlEngine);
|
||||
ProfileFreeze (RTI_TRUE, pi, xmlEngine);
|
||||
|
||||
return (RTI_TRUE);
|
||||
|
||||
#undef CLOCK_NAME_LEN
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
void ProfileCleanup (void* xmlEngine)
|
||||
{
|
||||
ActivePIList *tmp = activePI, *curr= activePI;
|
||||
|
||||
/* delete all active profiles */
|
||||
while(tmp) {
|
||||
tmp = tmp->next;
|
||||
(void)ProfileKill (curr->pi, xmlEngine);
|
||||
curr = tmp;
|
||||
}
|
||||
|
||||
/* reset globals */
|
||||
ProfileLastPI = 0;
|
||||
activePI = 0;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
RTIBool ProfileSetIgnore (unsigned int* array, int size, ignoreType type,
|
||||
ProfileInfo pi, const void* xmlEngine)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int * tmp = NULL;
|
||||
unsigned int * pInt = NULL;
|
||||
RTIBool ret = RTI_TRUE;
|
||||
|
||||
/* allocate space for new set */
|
||||
if (size) {
|
||||
pInt = (unsigned int*) malloc_KERNEL (sizeof(unsigned int) * size);
|
||||
if (pInt == NULL) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* acquire OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteLock(pi->opi); /* ===(P)=== */
|
||||
#else
|
||||
OSPreemptLock(pi->opi); /* ===(P)=== */
|
||||
#endif
|
||||
|
||||
if (type == IGNORE_CPU) {
|
||||
if (pi->ignoreCpus.id) {
|
||||
free_KERNEL (pi->ignoreCpus.id);
|
||||
}
|
||||
pi->ignoreCpus.id = pInt;
|
||||
tmp = pi->ignoreCpus.id;
|
||||
pi->ignoreCpus.size = size;
|
||||
} else if (type == IGNORE_UID) {
|
||||
if (pi->ignoreUids.id) {
|
||||
free_KERNEL (pi->ignoreUids.id);
|
||||
}
|
||||
pi->ignoreUids.id = pInt;
|
||||
tmp = pi->ignoreUids.id;
|
||||
pi->ignoreUids.size = size;
|
||||
} else if (type == IGNORE_TID) {
|
||||
if (pi->ignoreTids.id) {
|
||||
free_KERNEL (pi->ignoreTids.id);
|
||||
}
|
||||
pi->ignoreTids.id = pInt;
|
||||
tmp = pi->ignoreTids.id;
|
||||
pi->ignoreTids.size = size;
|
||||
}
|
||||
|
||||
if (size && !tmp) {
|
||||
ret = RTI_FALSE;
|
||||
} else {
|
||||
while (i < size) {
|
||||
tmp[i] = array[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteUnlock (pi->opi); /* ===P=== */
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi); /* ===P=== */
|
||||
#endif
|
||||
|
||||
if (!ret) {
|
||||
v0printf ("ProfileSetIgnore: failed to allocate memory for list.\n");
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
int ProfileMsgsReceive (void *buffer, unsigned int bufsize)
|
||||
{
|
||||
int size = 0, tmpsize = bufsize;
|
||||
ActivePIList *tmp = activePI;
|
||||
|
||||
while (tmp && (bufsize > 0)) {
|
||||
/* distribute bufsize to each cpu uniformly (for now) */
|
||||
size = RTIMsgQReceive (tmp->pi->msgQ, buffer, bufsize);
|
||||
|
||||
if (size) {
|
||||
/* Do OS-specific processing on each sample in msgQ */
|
||||
OSProcessSamples (buffer, size, tmp->pi->opi);
|
||||
}
|
||||
bufsize -= size;
|
||||
buffer = ((char*) buffer) + size;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
/* send the no. of bytes filled up in buffer */
|
||||
return (tmpsize - bufsize);
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
int ProfileGetStatus (void *buffer, unsigned int bufsize, ProfileInfo pi,
|
||||
const void* xmlEngine)
|
||||
{
|
||||
#define BUF_LEN (256)
|
||||
char msgstr[BUF_LEN];
|
||||
int len;
|
||||
|
||||
if ((pi = ProfileGetLastPI (pi, "ProfileGetStatus")) == 0) {
|
||||
v0printf ("ProfileGetStatus: No ProfileInfo object!\n");
|
||||
return (0);
|
||||
}
|
||||
if (buffer == NULL) {
|
||||
v0printf ("ProfileGetStatus: No return buffer!\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined(RTI_VXWORKS)
|
||||
len = snprintf(msgstr, BUF_LEN,
|
||||
#else
|
||||
len = ST_snprintf(msgstr, BUF_LEN,
|
||||
#endif
|
||||
"<Status sampleRate=\"%u\" contextErr=\"%u\" "
|
||||
"bufferErr=\"%u\" depthErr=\"%u\" interruptErr=\"%u\">"
|
||||
"</Status>",
|
||||
pi->sampleRate, pi->contextErr, pi->bufferErr, pi->depthErr,
|
||||
pi->interruptErr);
|
||||
|
||||
if (len >= BUF_LEN) {
|
||||
v0printf ("ProfileGetStatus: Out of buffer space composing status "
|
||||
"message; contact support@windriver.com\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
copy_to_agent (buffer, msgstr, len);
|
||||
|
||||
return (len);
|
||||
#undef BUF_LEN
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
ProfileInfo ProfileInit (char* clock, unsigned int* tids, int tidListSize,
|
||||
RTIBool irqSampling, int sampleRate, int maxSamples,
|
||||
int maxStack, const void* xmlEngine)
|
||||
{
|
||||
ProfileInfo pi;
|
||||
int msglen;
|
||||
int cpus = OSGetNumCPUs();
|
||||
#ifdef SMP_CONFIG
|
||||
unsigned int tabooTids[2] = {(unsigned int)PROFILE_IDLE_TID,
|
||||
(unsigned int)PROFILE_KERNEL_TID};
|
||||
#endif
|
||||
|
||||
v1printf ("ProfileScope version " SCOPEPROFILEVERSION "\n");
|
||||
v1printf ("(c) Copyright %s, Wind River Systems Inc.\n", &__DATE__[7]);
|
||||
|
||||
if (maxSamples <= 0) {
|
||||
maxSamples = 1024;
|
||||
}
|
||||
if (maxStack <= 0 || maxStack > PROFILE_MAX_STACK_DEPTH) {
|
||||
maxStack = PROFILE_MAX_STACK_DEPTH;
|
||||
}
|
||||
|
||||
/* allocate space for a profile instance */
|
||||
pi = malloc_KERNEL (sizeof(struct ProfileInfoStorage));
|
||||
if (pi == NULL) {
|
||||
v0printf ("Can't allocate ProfileInfo.\n");
|
||||
return (0);
|
||||
}
|
||||
pi->opi = OSProfileInit (irqSampling);
|
||||
if (pi->opi == 0) {
|
||||
v0printf ("Can't allocate OSProfileInfo.\n");
|
||||
free_KERNEL (pi);
|
||||
return (0);
|
||||
}
|
||||
|
||||
pi->profileTidList = (int*) malloc_KERNEL (sizeof(int) * tidListSize);
|
||||
if (pi->profileTidList == NULL) {
|
||||
OSProfileKill (pi->opi);
|
||||
free_KERNEL (pi);
|
||||
v0printf ("Can't allocate profileTidList.\n");
|
||||
return (0);
|
||||
}
|
||||
pi->acProfileTidList = (int*) malloc_KERNEL (sizeof(int) * tidListSize);
|
||||
if (pi->acProfileTidList == NULL) {
|
||||
OSProfileKill (pi->opi);
|
||||
free_KERNEL (pi->profileTidList);
|
||||
free_KERNEL (pi);
|
||||
v0printf ("Can't allocate acProfileTidList.\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* allocate mesg queue for each of the cpu */
|
||||
msglen = PROFILE_MSG_HDR_SIZE + (sizeof(void*) * maxStack);
|
||||
pi->msgQ = RTIMsgQCreate (maxSamples*cpus, msglen);
|
||||
if (pi->msgQ == NULL) {
|
||||
OSProfileKill (pi->opi);
|
||||
free_KERNEL (pi->acProfileTidList);
|
||||
free_KERNEL (pi->profileTidList);
|
||||
free_KERNEL (pi);
|
||||
v0printf ("Can't allocate Message Queue.\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* initialize other member variables */
|
||||
pi->sampleFlag = RTI_TRUE;
|
||||
pi->maxStack = maxStack;
|
||||
pi->maxSamples = maxSamples;
|
||||
pi->sampleRate = sampleRate;
|
||||
pi->clock = 0;
|
||||
pi->tidListSize = tidListSize;
|
||||
pi->ignoreCpus.id = NULL;
|
||||
pi->ignoreCpus.size = 0;
|
||||
pi->ignoreUids.id = NULL;
|
||||
pi->ignoreUids.size = 0;
|
||||
pi->ignoreTids.id = NULL;
|
||||
pi->ignoreTids.size = 0;
|
||||
pi->timer.count = 0;
|
||||
|
||||
pi->takingSample = RTI_FALSE;
|
||||
pi->contextErr = 0;
|
||||
pi->bufferErr = 0;
|
||||
pi->depthErr = 0;
|
||||
pi->fpMemErr = 0;
|
||||
pi->pcMemErr = 0;
|
||||
pi->interruptErr = 0;
|
||||
pi->sampleErr = 0;
|
||||
|
||||
/* add pi to active profiles list */
|
||||
ProfileAddPI (pi);
|
||||
|
||||
/* set profile mode */
|
||||
if (ProfileSetMode (tids, tidListSize, irqSampling, RTI_TRUE, pi,
|
||||
xmlEngine) == RTI_FALSE)
|
||||
{
|
||||
(void)ProfileKill (pi, xmlEngine);
|
||||
v0printf ("Can't set mode.\n");
|
||||
return (0);
|
||||
}
|
||||
ProfileClear (pi, xmlEngine);
|
||||
|
||||
#ifdef SMP_CONFIG
|
||||
/* explicitly add two special task IDs which should never be traced */
|
||||
if (!ProfileSetIgnore (tabooTids, 2, IGNORE_TID, pi, xmlEngine)) {
|
||||
ProfileKill (pi, xmlEngine);
|
||||
v0printf ("Can't set ignored task IDs.\n");
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ProfileConnectClk (clock, pi, xmlEngine) == RTI_FALSE) {
|
||||
v0printf ("Can't connect clock.\n");
|
||||
ProfileKill (pi, xmlEngine);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (pi);
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/* profileapi.pkg.h - built from: profileapi.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef profileapi_pkg_h
|
||||
#define profileapi_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <rtitools/rtitools_msgq.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
|
||||
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
# undef SMP_CONFIG
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define PROFILE_MAX_STACK_DEPTH (64)
|
||||
|
||||
typedef enum
|
||||
{ IGNORE_TID = 1,
|
||||
IGNORE_UID,
|
||||
IGNORE_CPU
|
||||
} ignoreType;
|
||||
|
||||
typedef enum {
|
||||
IDLE_THREAD = 1,
|
||||
KERNEL_THREAD,
|
||||
USER_THREAD,
|
||||
KERNEL_INTERRUPT,
|
||||
KERNEL_EXCEPTION,
|
||||
KERNEL_STATE
|
||||
} ProfileEntity;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
IRQ_ROUND_ROBIN = 1,
|
||||
IRQ_ALL_CPUS,
|
||||
IRQ_UNKNOWN
|
||||
} irqPolicy;
|
||||
|
||||
typedef struct {
|
||||
unsigned long ticks;
|
||||
unsigned long* count;
|
||||
unsigned short on;
|
||||
} SoftTimer;
|
||||
|
||||
typedef struct {
|
||||
unsigned int* id;
|
||||
unsigned int size;
|
||||
} ignoreList;
|
||||
|
||||
struct OSProfileInfoStorage;
|
||||
typedef struct OSProfileInfoStorage* OSProfileInfo;
|
||||
|
||||
struct ProfileInfoStorage {
|
||||
OSProfileInfo opi; /* OS-specific data structure */
|
||||
|
||||
int * profileTidList; /* useful in single thread/process mode, to
|
||||
determine which thread/process to sample */
|
||||
int * acProfileTidList; /* At a given instance, this is a copy
|
||||
of profileTidList */
|
||||
int tidListSize;
|
||||
RTIBool tidListChanged; /* flag indicating that profileTidList has
|
||||
changed */
|
||||
|
||||
char* clock; /* clock string pointing to sample clock */
|
||||
SoftTimer timer; /* software timer to sub-sample from max clock
|
||||
(system/aux) frequency */
|
||||
|
||||
ignoreList ignoreCpus; /* list of currently ignored CPUs */
|
||||
ignoreList ignoreUids; /* list of currently ignored user ids */
|
||||
ignoreList ignoreTids; /* list of currently ignored thread ids */
|
||||
|
||||
RTIBool sampleFlag; /* to activate/de-activate sampling */
|
||||
RTIBool irqSampling; /* whether sampling in interrupt or not*/
|
||||
RTIBool takingSample; /* flag to know if we are missing interrupt */
|
||||
|
||||
int maxSamples; /* maximum samples to collect before overflow */
|
||||
int maxStack; /* <= 64 */
|
||||
int sampleRate;
|
||||
|
||||
/* error count */
|
||||
unsigned int contextErr; /* Increment when a context trace fails. */
|
||||
unsigned int bufferErr; /* Increment when samples buffer is full. */
|
||||
unsigned int depthErr; /* Increment if stack deeper than maxStack. */
|
||||
unsigned int fpMemErr; /* Increment if fp out of bounds. */
|
||||
unsigned int pcMemErr; /* Increment if pc out of bounds. */
|
||||
unsigned int interruptErr; /* Increment if new interrupt happens, when
|
||||
previous interrupt is being processed */
|
||||
unsigned int sampleErr; /* Increment if sampled context corresponds to
|
||||
context of sampler thread (can't context
|
||||
trace in such case) */
|
||||
|
||||
RTIMsgQHdrPtr msgQ; /* A message queue to store samples */
|
||||
};
|
||||
|
||||
#define v1printf if (ProfileDebuggingOutput >= 1) v0printf
|
||||
#define v2printf if (ProfileDebuggingOutput >= 2) v0printf
|
||||
#define v3printf if (ProfileDebuggingOutput >= 3) v0printf
|
||||
|
||||
#define PROFILE_MSG_HDR_SIZE ((int) &((ProfileMsgStorage *) 0)->stack)
|
||||
|
||||
|
||||
|
||||
typedef struct ProfileInfoStorage* ProfileInfo;
|
||||
|
||||
extern int ProfileDebuggingOutput;
|
||||
|
||||
|
||||
/**
|
||||
* ProfileFreeze - freeze (halt) or resume sampling
|
||||
*
|
||||
* This routine sets a Boolean flag controling sampling to the specified value
|
||||
* which either enables sampling (sample = RTI_TRUE) or disables sampling
|
||||
* (sample = RTI_FALSE).
|
||||
*
|
||||
* RETURN
|
||||
* RTI_TRUE - operation successful
|
||||
* RTI_FALSE - wrong tool
|
||||
*/
|
||||
extern RTIBool ProfileFreeze (RTIBool sample, ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileClear (ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileSetMode (
|
||||
unsigned int * tids, /* task/thread ID list */
|
||||
int size, /* number of IDs in list */
|
||||
RTIBool irqSampling, /* IRQ sampling allowed? */
|
||||
RTIBool dontClear, /* clear profile info after setting mode? */
|
||||
ProfileInfo pi,
|
||||
const void * xmlEngine);
|
||||
|
||||
|
||||
extern int ProfileSetSampleRate (int requestedSR, ProfileInfo pi,
|
||||
const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileKill (ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileConnectClk (char* clock, ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileCleanup (void* xmlEngine);
|
||||
|
||||
|
||||
extern RTIBool ProfileSetIgnore (unsigned int* array, int size, ignoreType type,
|
||||
ProfileInfo pi, const void* xmlEngine);
|
||||
|
||||
|
||||
extern int ProfileMsgsReceive (void *buffer, unsigned int bufsize);
|
||||
|
||||
|
||||
extern int ProfileGetStatus (void *buffer, unsigned int bufsize, ProfileInfo pi,
|
||||
const void* xmlEngine);
|
||||
|
||||
|
||||
extern ProfileInfo ProfileInit (char* clock, unsigned int* tids, int tidListSize,
|
||||
RTIBool irqSampling, int sampleRate, int maxSamples,
|
||||
int maxStack, const void* xmlEngine);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* profileapi_pkg_h */
|
||||
@@ -0,0 +1,545 @@
|
||||
/* profilesample.c - ProfileScope sampler code. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
------------------------
|
||||
01e,30oct13,elp Checked ST_context_create() return value
|
||||
01d,29aug11,jfu Fix call stack sending issue when the context top is
|
||||
reached
|
||||
01c,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
01b,13aug10,flu Add vxTaskEntry to stack crawl when
|
||||
RTITOOLS_CONTEXT_CHECK_TOP_LAST is true.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
34a,01jul09,wzc Fix coverity prevent error RESERVE NULL in line 130
|
||||
34a,27aug08,mas added vsbConfig.h; changed _WRS_XV_SMP to _WRS_CONFIG_SMP
|
||||
33a,30jan07,mas made SMP-compliant
|
||||
20a,28oct04,avd Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
ProfileScope sampler code.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <st_stacktrace.h>
|
||||
|
||||
#include "profileapi.pkg.h"
|
||||
#include "profile_arch.h"
|
||||
#include "profile.pkg.h"
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
# include <rtilib/vxVersions.h>
|
||||
# include <vxWorks.h>
|
||||
# undef SMP_CONFIG
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* defines */
|
||||
|
||||
/* Use unique pid values for interrupts and exceptions. These numbers should
|
||||
work with the linux 2.6 kernel that is supposed to have 2x10^9 pids. */
|
||||
#define PID_INTERRUPT (0x77359405) /* Hex for 2x10^9 + 5. */
|
||||
#define PID_EXCEPTION (0x77359406) /* Hex for 2x10^9 + 6. */
|
||||
|
||||
/* Enable task stop prior to tracing stack */
|
||||
#define TASK_STOP
|
||||
|
||||
/* dummy functions for ignored threads and truncated callstacks */
|
||||
void IGNORED(void) {}
|
||||
void truncated_callstacks(void) {}
|
||||
|
||||
|
||||
/*
|
||||
* Debug and testing flag:
|
||||
* This ST_TEST_MODE symbol can be set to '1' by the developer or tester
|
||||
* from the gmake command line to enable using development features and
|
||||
* testing code: make <target> "RTI_TESTING_FLAG = '-DST_TEST_MODE=1'"
|
||||
*/
|
||||
#ifndef ST_TEST_MODE
|
||||
# define ST_TEST_MODE (0) /* 0 for production, non-zero for testing and dev. */
|
||||
#endif
|
||||
|
||||
#if ST_TEST_MODE
|
||||
/* Global struct for reporting info back to user. */
|
||||
struct ContextSamplerTest {
|
||||
int errorCount;
|
||||
int traceCount;
|
||||
int missedTopCount;
|
||||
} contextSamplerTestStatus = {0, 0, -1};
|
||||
|
||||
/* Function to handle outputting context sampler test status info
|
||||
when requested by the user via the /proc file system. */
|
||||
|
||||
int context_sampler_test_read_proc(char *page, char **start, int offset,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len += sprintf(page, "traceCount = %d, errorCount = %d, missedTopCount = %d\n", contextSamplerTestStatus.traceCount, contextSamplerTestStatus.errorCount, contextSamplerTestStatus.missedTopCount);
|
||||
*eof = 1;
|
||||
return len;
|
||||
}
|
||||
#endif /* ST_TEST_MODE */
|
||||
|
||||
|
||||
Private
|
||||
RTIBool BinSearch(unsigned int* ptr, int size, unsigned int val)
|
||||
{
|
||||
RTIBool result = RTI_FALSE;
|
||||
int low = 0, high = size-1;
|
||||
|
||||
if ((ptr[low] < val) && (ptr[high] > val)) {
|
||||
while (1) {
|
||||
if (low == high) {
|
||||
if (ptr[low] == val) {
|
||||
result = RTI_TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ptr[low] == val || ptr[high] == val) {
|
||||
result = RTI_TRUE;
|
||||
break;
|
||||
}
|
||||
if (ptr[(low+high)>>1] < val)
|
||||
low = (low+high) >> 1;
|
||||
else if (ptr[(low+high)>>1] > val)
|
||||
high = (low+high) >> 1;
|
||||
else if (ptr[(low+high)>>1] == val) {
|
||||
result = RTI_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void ProfileTraceNCollectSample(ProfileInfo pi)
|
||||
{
|
||||
int cpu;
|
||||
int tid;
|
||||
int euid;
|
||||
RTIBool ignore = RTI_FALSE, checkIfInterrupt = RTI_FALSE;
|
||||
RTIBool systemMode = RTI_FALSE, sendMsg = RTI_FALSE;
|
||||
ProfileMsgStorage msg;
|
||||
ST_context temp1, temp2;
|
||||
ST_context * context = &temp1;
|
||||
ST_context * parent = &temp2;
|
||||
int i = 0;
|
||||
int sendStatus = 0;
|
||||
int status = ST_CONTEXT_OK;
|
||||
|
||||
/* sanity check */
|
||||
if (pi == 0) { return; }
|
||||
if (OSGetSamplerTid (pi->opi) == OSGetCurrentTid (pi->opi)) {
|
||||
pi->sampleErr++;
|
||||
return;
|
||||
}
|
||||
|
||||
cpu = OSGetCurrentCPU();
|
||||
tid = OSGetCurrentTid(pi->opi);
|
||||
euid = OSGetCurrentEuid(pi->opi);
|
||||
|
||||
/* acquire OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptReadLock(pi->opi);
|
||||
#else
|
||||
OSPreemptLock(pi->opi);
|
||||
#endif
|
||||
|
||||
/* check if the thread to sample is to be ignored or not */
|
||||
if (pi->ignoreCpus.size > 0 &&
|
||||
(BinSearch(pi->ignoreCpus.id, pi->ignoreCpus.size, cpu) == RTI_TRUE))
|
||||
{
|
||||
ignore = RTI_TRUE;
|
||||
}
|
||||
if (pi->ignoreTids.size > 0 &&
|
||||
BinSearch(pi->ignoreTids.id, pi->ignoreTids.size, tid) == RTI_TRUE)
|
||||
{
|
||||
if (!OSIsAddrInKernel(OSGetCurrentPC(pi->opi), pi->opi)) {
|
||||
ignore = RTI_TRUE;
|
||||
} else {
|
||||
checkIfInterrupt = RTI_TRUE;
|
||||
}
|
||||
}
|
||||
if (pi->ignoreUids.size > 0 &&
|
||||
BinSearch(pi->ignoreUids.id, pi->ignoreUids.size, euid) == RTI_TRUE)
|
||||
{
|
||||
if (!OSIsAddrInKernel(OSGetCurrentPC(pi->opi), pi->opi)) {
|
||||
ignore = RTI_TRUE;
|
||||
} else {
|
||||
checkIfInterrupt = RTI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pi->acProfileTidList[0] == -1) {
|
||||
systemMode = RTI_TRUE;
|
||||
}
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptReadUnlock(pi->opi);
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi);
|
||||
#endif
|
||||
|
||||
sendMsg = OSPopulateMsgStruct(pi->opi, &msg, systemMode);
|
||||
|
||||
if (ignore == RTI_TRUE) {
|
||||
send_ignore:
|
||||
|
||||
msg.stack[0] = IGNORED;
|
||||
msg.numSamples = 1;
|
||||
goto send_msg;
|
||||
} else if (sendMsg == RTI_TRUE) {
|
||||
goto send_msg;
|
||||
}
|
||||
|
||||
#if ST_TEST_MODE
|
||||
/* Count only valid trace attempts. */
|
||||
contextSamplerTestStatus.traceCount++;
|
||||
#endif /* ST_TEST_MODE */
|
||||
|
||||
#if defined(SMP_CONFIG) && defined(TASK_STOP)
|
||||
/* stop task so we have stable context */
|
||||
if (taskStopForce (tid) != OK) {
|
||||
goto send_ignore; /* unbreakable task */
|
||||
}
|
||||
|
||||
/* if sampling was disabled while waiting for task to stop, quit */
|
||||
if (pi->sampleFlag == RTI_FALSE) { return; }
|
||||
#endif
|
||||
|
||||
/* FUTURE: If one or more clock ticks between tick ISR and here,
|
||||
* add statistical weight to sample equal to number of ticks.
|
||||
* msg.sampleWeight = pi->interruptErr - pi->opi->spinTicks;
|
||||
*/
|
||||
|
||||
/* create stack walk context */
|
||||
if (!ST_context_create(OSGetCurrentRegs(pi->opi),
|
||||
(unsigned long) OSGetCurrentTask(pi->opi),
|
||||
RTI_FALSE, context))
|
||||
return;
|
||||
|
||||
msg.stack[0] = (void *)context->pc;
|
||||
|
||||
/* switch to user process if necessary */
|
||||
OSContextSwitch(pi->opi, RTI_TRUE);
|
||||
|
||||
/* Walk the task stack from current SP to base, one frame at a time,
|
||||
* and send everything to msg queue.
|
||||
*/
|
||||
for (i = 1; i < pi->maxStack; i++) {
|
||||
ST_context * tempContext;
|
||||
|
||||
/* get previous (parent) stack frame context based on current */
|
||||
status = ST_CallingContextGet (context, parent);
|
||||
|
||||
if (status == ST_CONTEXT_OK) {
|
||||
if ((checkIfInterrupt == RTI_TRUE) &&
|
||||
(!OSIsAddrInKernel(((unsigned long) parent->pc), pi->opi)))
|
||||
{
|
||||
/* switch back to the context of the sampler task */
|
||||
ST_context_delete(context);
|
||||
#if defined(SMP_CONFIG) && defined(TASK_STOP)
|
||||
/* let task continue running */
|
||||
taskCont (tid);
|
||||
#endif
|
||||
goto send_ignore;
|
||||
}
|
||||
msg.stack[i] = (void *)parent->pc;
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
} else if (status == ST_CONTEXT_KERNEL_OK) {
|
||||
if ((checkIfInterrupt == RTI_TRUE) &&
|
||||
(!OSIsAddrInKernel (((unsigned long) parent->pc), pi->opi)))
|
||||
{
|
||||
/* switch back to the context of the sampler task */
|
||||
ST_context_delete (context);
|
||||
goto send_ignore;
|
||||
}
|
||||
msg.stack[i] = (void *)parent->pc;
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
context->leaf = RTI_TRUE;
|
||||
} else if (status == ST_CONTEXT_TOP) {
|
||||
if(RTITOOLS_CONTEXT_CHECK_TOP_LAST)
|
||||
{
|
||||
if (parent->pc == 0) {
|
||||
msg.stack[i] = truncated_callstacks;
|
||||
pi->contextErr++;
|
||||
#if ST_TEST_MODE
|
||||
contextSamplerTestStatus.errorCount++;
|
||||
#endif /* ST_TEST_MODE */
|
||||
}else
|
||||
msg.stack[i] = (void *)parent->pc;
|
||||
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
} else if (status == ST_CONTEXT_ERROR) {
|
||||
msg.stack[i++] = truncated_callstacks;
|
||||
pi->contextErr++;
|
||||
#if ST_TEST_MODE
|
||||
contextSamplerTestStatus.errorCount++;
|
||||
#endif /* ST_TEST_MODE */
|
||||
break;
|
||||
} else if (status == ST_CONTEXT_INTERRUPT_TOP) {
|
||||
msg.pentity = KERNEL_INTERRUPT;
|
||||
msg.tid = PID_INTERRUPT;
|
||||
msg.pid = PID_INTERRUPT;
|
||||
#ifdef RTI_LINUX
|
||||
msg.euid = 0;
|
||||
#endif
|
||||
msg.stack[i]= (void *)parent->pc;
|
||||
i++;
|
||||
break;
|
||||
} else if (status == ST_CONTEXT_EXCEPTION_TOP) {
|
||||
#if defined (RTI_LINUX)
|
||||
msg.pentity = KERNEL_EXCEPTION;
|
||||
msg.tid = PID_EXCEPTION;
|
||||
msg.pid = PID_INTERRUPT;
|
||||
msg.euid = 0;
|
||||
i -= 1;
|
||||
break;
|
||||
#elif defined(RTI_VXWORKS)
|
||||
if (parent->pc == 0) {
|
||||
msg.stack[i] = truncated_callstacks;
|
||||
pi->contextErr++;
|
||||
#if ST_TEST_MODE
|
||||
contextSamplerTestStatus.errorCount++;
|
||||
#endif /* ST_TEST_MODE */
|
||||
break;
|
||||
}
|
||||
|
||||
msg.stack[i] = (void *)parent->pc;
|
||||
parent->pc = parent->gpregs[REG_LR];
|
||||
tempContext = context;
|
||||
context = parent;
|
||||
parent = tempContext;
|
||||
#else
|
||||
# error Unknown OS
|
||||
#endif
|
||||
}
|
||||
}
|
||||
msg.numSamples = i;
|
||||
|
||||
#if defined(SMP_CONFIG) && defined(TASK_STOP)
|
||||
/* let task continue running */
|
||||
taskCont (tid);
|
||||
#endif
|
||||
|
||||
/* switch back to the context of the sampler task */
|
||||
ST_context_delete (context);
|
||||
|
||||
/* switch back to kernel domain if necessary */
|
||||
OSContextSwitch (pi->opi, RTI_FALSE);
|
||||
|
||||
send_msg:
|
||||
|
||||
/* acquire OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptLock (pi->opi);
|
||||
#else
|
||||
OSPreemptLock (pi->opi);
|
||||
#endif
|
||||
|
||||
/* store the sample to msg queue */
|
||||
sendStatus = RTIMsgQSend (pi->msgQ, (void*) &msg, PROFILE_MSG_HDR_SIZE +
|
||||
(msg.numSamples * sizeof(void*)));
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
OSPreemptUnlock (pi->opi);
|
||||
|
||||
/* update statistics */
|
||||
if (sendStatus == RTI_MSGQ_FULL) {
|
||||
pi->bufferErr++;
|
||||
}
|
||||
if ((i == pi->maxStack) && (status == ST_CONTEXT_OK ||
|
||||
status == ST_CONTEXT_ERROR ||
|
||||
status == ST_CONTEXT_KERNEL_OK) )
|
||||
{
|
||||
pi->depthErr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void ProfileTakeSample (ProfileInfo pi)
|
||||
{
|
||||
unsigned int size = pi->tidListSize;
|
||||
unsigned int i;
|
||||
unsigned int tid;
|
||||
|
||||
/* if profileTidList has new thread ids to profile, copy the list */
|
||||
if (pi->tidListChanged == RTI_TRUE) {
|
||||
/* acquire OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteLock(pi->opi);
|
||||
#else
|
||||
OSPreemptLock(pi->opi);
|
||||
#endif
|
||||
|
||||
/* update task ID list */
|
||||
for (i = 0; i < size; i++) {
|
||||
pi->acProfileTidList[i] = pi->profileTidList[i];
|
||||
}
|
||||
pi->tidListChanged = RTI_FALSE;
|
||||
|
||||
/* release OS-specific pre-emption lock */
|
||||
#ifdef SMP_CONFIG
|
||||
OSPreemptWriteUnlock(pi->opi);
|
||||
#else
|
||||
OSPreemptUnlock(pi->opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Trace the current thread on the current cpu in system-mode
|
||||
* profiling. If running in single thread/process mode, trace
|
||||
* all the selected threads (in GUI).
|
||||
*/
|
||||
for (i = 0; i < size; i++) {
|
||||
tid = pi->acProfileTidList[i];
|
||||
|
||||
/* system-mode profiling */
|
||||
if (tid == ~0) {
|
||||
ProfileTraceNCollectSample (pi);
|
||||
pi->takingSample = RTI_FALSE;
|
||||
return; /* system mode has only one tid, despite what size says */
|
||||
}
|
||||
/* single thread/process profiling */
|
||||
else {
|
||||
/* Find the corresponding thread. Note that this call
|
||||
* will also change value of activeThread in OSProfileInfo
|
||||
* structure to point to this thread.
|
||||
*/
|
||||
if (OSFindThread (tid, pi->opi) == RTI_FALSE) {
|
||||
pi->takingSample = RTI_FALSE;
|
||||
return;
|
||||
}
|
||||
ProfileTraceNCollectSample (pi);
|
||||
}
|
||||
}
|
||||
|
||||
/* ready for next sample IRQ */
|
||||
pi->takingSample = RTI_FALSE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* ProfileRunSamplerThread - execute the sampler thread
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Entry function for the sampler thread that periodically samples the
|
||||
* system at the set sample frequency. At present, only VxWorks supports
|
||||
* sampling by a separate thread. On Linux, sampling is done in the interrupt.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
void ProfileRunSamplerThread (ProfileInfo pi)
|
||||
{
|
||||
/* runs in an infinite loop */
|
||||
while (1) {
|
||||
/* wait to be synchronized */
|
||||
OSWaitSamplerThread (pi->opi);
|
||||
|
||||
ProfileTakeSample (pi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
************************** INTERRUPT CONTEXT **********************************
|
||||
*******************************************************************************
|
||||
*
|
||||
* ProfileSample - handle the sampler clock interrupt
|
||||
*
|
||||
* DESCRIPTION
|
||||
* ISR for the sampler clock. Selects task to profile. By default, task
|
||||
* to be profiled is the task that was interrupted by us.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
Package
|
||||
#ifdef RTI_LINUX
|
||||
void ProfileSample (ProfileInfo pi, RTI_pt_regs_p ptregs)
|
||||
#elif defined(RTI_VXWORKS)
|
||||
void ProfileSample (ProfileInfo pi)
|
||||
#endif
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (pi == 0 || pi->sampleFlag == RTI_FALSE) { return; }
|
||||
|
||||
/* get CPU index we're running on */
|
||||
cpu = OSGetCurrentCPU();
|
||||
|
||||
/* decrement timer count */
|
||||
pi->timer.count[cpu] -= 1;
|
||||
if (pi->timer.on && (pi->timer.count[cpu] <= 0)) {
|
||||
pi->timer.count[cpu] = pi->timer.ticks;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pi->takingSample == RTI_TRUE) {
|
||||
pi->interruptErr++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Capture the current thread running on the system */
|
||||
#ifdef RTI_LINUX
|
||||
OSCreateContext (pi->opi, ptregs);
|
||||
#elif defined(RTI_VXWORKS)
|
||||
/* This call checks for the sampler task ID, so we don't need to */
|
||||
if (!OSCreateContext (pi->opi, pi->interruptErr)) {
|
||||
pi->sampleErr++;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
pi->takingSample = RTI_TRUE;
|
||||
|
||||
/* If doing process sampling, run the sampler thread.
|
||||
* (Currently works on only VxWorks)
|
||||
*/
|
||||
if (pi->irqSampling == RTI_FALSE) {
|
||||
OSRunSamplerThread (pi->opi);
|
||||
}
|
||||
|
||||
/* If sampling in the interrupt, sample synchronously.
|
||||
* (Currently works only on Linux)
|
||||
*/
|
||||
else {
|
||||
ProfileTakeSample (pi);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* profilesample.pkg.h - built from: profilesample.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef profilesample_pkg_h
|
||||
#define profilesample_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* ProfileRunSamplerThread - execute the sampler thread
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Entry function for the sampler thread that periodically samples the
|
||||
* system at the set sample frequency. At present, only VxWorks supports
|
||||
* sampling by a separate thread. On Linux, sampling is done in the interrupt.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
extern void ProfileRunSamplerThread (ProfileInfo pi);
|
||||
|
||||
|
||||
#ifdef RTI_LINUX
|
||||
extern void ProfileSample (ProfileInfo pi, RTI_pt_regs_p ptregs);
|
||||
#elif defined(RTI_VXWORKS)
|
||||
extern void ProfileSample (ProfileInfo pi);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* profilesample_pkg_h */
|
||||
@@ -0,0 +1,29 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../../..
|
||||
|
||||
LIB_BASE_NAME = profile
|
||||
|
||||
EXTRA_DEFINE += -DSCOPEPROFILEVERSION=\"4.11a\"
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include/vx \
|
||||
-I$(COMP_STACKTRACE_PATH)/include \
|
||||
-I..
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= profile.o
|
||||
|
||||
PKG_H =
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
@@ -0,0 +1,896 @@
|
||||
/* profile.c - OS-specific profiling interface code. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2011, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01d,10oct13,wzc Fix prevent warnings.
|
||||
01c,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
01b,16dec10,zlo Use new typed error value (WIND00246074)
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
6.7.2a,18dec08,mas fixed memory leak (WIND00147287)
|
||||
6.7d,02oct08,mas Added Context Cache Support and _WRS_CONFIG_SMP + vsbConfig.h
|
||||
6.7c,19jul08,pca Fixed compilation for SMP targets by removing makeheader-
|
||||
specific tokens from the generated package header file.
|
||||
6.7b,11jul08,pca Include makeheader.h after the Vx headers, so Vx's macro-ized
|
||||
include directive generation isn't interfered with.
|
||||
6.7a,16may08,tpw copied to CC from CVS repository label clearcase_drop_24apr08
|
||||
34a,27aug08,mas added vsbConfig.h; changed _WRS_XV_SMP to _WRS_CONFIG_SMP;
|
||||
removed redundant call to stContextUninit()
|
||||
33a,30jan07,mas made SMP-compliant
|
||||
20a,28oct04,avd Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
This library contains OS-specific functions for use by ProfileScope
|
||||
on a target.
|
||||
|
||||
INTERNAL
|
||||
Special consideration was given to the selection of the locking mechanisms
|
||||
for use on VxWorks SMP systems. The locks are valid for the case where
|
||||
only one instance of ProfileScope (PS) is allowed to run on one particular
|
||||
CPU (CPU affinity).
|
||||
|
||||
Preventing task pre-emption in PS is actually a case of locking internal
|
||||
data from change caused by another part of the system. Typically this is
|
||||
via calls from the GUI going through the WDB task. There are no changes
|
||||
to internal data tables due to any other part of PS (including exceptions),
|
||||
so using a mutex semaphore to lock writing access to internal data tables
|
||||
is sufficient for a single-instance PS and would probably work on a multi-
|
||||
instance tool. But, because semaphores have so much overhead, the use of
|
||||
a task spinlock was examined. However, because no blocking system calls
|
||||
or system calls using their own spinlocks (including logMsg, semTake, malloc,
|
||||
and free) can be made during a task spinlock, it was decided to use a
|
||||
self-enforced binary semaphore based on the cas (compare and swap) atomic
|
||||
operator. Any task attempting to access internal data structures and tables
|
||||
and which fails to aquire the semaphore, must put itself into a spin loop.
|
||||
|
||||
A thread list is an internal data table that is accessed while task
|
||||
pre-emption is locked (a private spinlock is held), so no extra thread list
|
||||
locking is required. Therefore, OSThreadListLock/Unlock calls are no-ops.
|
||||
|
||||
NOTE
|
||||
If the design is changed to allow multiple instances to run or if no CPU
|
||||
affinity is set, these lock mechanisms and some of the library calls
|
||||
must be re-evaluated and changed as appropriate!
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "profileapi.pkg.h"
|
||||
#include "profilesample.pkg.h"
|
||||
|
||||
#pragma begin_Public
|
||||
|
||||
/* profilescope message format */
|
||||
typedef struct {
|
||||
ProfileEntity pentity; /* thread entity being profiled */
|
||||
int tid; /* thread id */
|
||||
int pid; /* process group id */
|
||||
int cpuid; /* cpu id */
|
||||
int numSamples; /* number of profile stack samples */
|
||||
void * stack[PROFILE_MAX_STACK_DEPTH]; /* stack samples */
|
||||
/* int sampleWeight; /@ #ticks between ISR and sample*/
|
||||
} ProfileMsgStorage, *ProfileMsg;
|
||||
|
||||
#pragma end_Public
|
||||
|
||||
#pragma begin_Package
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <regs.h>
|
||||
#include <intLib.h>
|
||||
#include <semLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <usrConfig.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <private/kernelBaseLibP.h>
|
||||
#include <private/kernelLibP.h>
|
||||
|
||||
#include <rtilib/vxVersions.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#pragma end_Package
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <rtitools/rtitools_clock.h>
|
||||
#include <st_stacktrace.h>
|
||||
|
||||
#pragma begin_Package
|
||||
|
||||
#include <rtilib/rti_types.h>
|
||||
#ifdef SMP_CONFIG
|
||||
# include <rtilib/stSpinLock.h>
|
||||
# include <cpuset.h>
|
||||
# include <vxCpuLib.h>
|
||||
# include <private/taskToolsUtilLibP.h>
|
||||
# define KERNEL_ID kernelIdGet()
|
||||
#else
|
||||
# define KERNEL_ID kernelId
|
||||
#endif
|
||||
|
||||
|
||||
/* Globals */
|
||||
struct OSProfileInfoStorage {
|
||||
WIND_TCB * activeThread; /* Thread to sample */
|
||||
unsigned long sysMemTop; /* cached value of sysMemTop() */
|
||||
int samplerTid; /* tid of sampler task */
|
||||
|
||||
RTIBool irqSampling; /* whether sampling in interrupt or not */
|
||||
SEM_ID sem; /* synchronization semaphore for sampler */
|
||||
unsigned int spinTicks; /* ISR missed tick# when task selected */
|
||||
#ifdef SMP_CONFIG
|
||||
st_rwLock taskRWLock; /* private R/W spinlock for SMP systems */
|
||||
st_preemptLock preemptLock; /* private preemption lock */
|
||||
atomic_t cpuCurrent; /* CPU# currently being profiled */
|
||||
atomic_t cpuNext; /* next CPU# to be profiled */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef SMP_CONFIG
|
||||
static int lockKey = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/* Defines */
|
||||
|
||||
/* Please don't remove put any spaces before the \, it breaks GCC < 3 */
|
||||
#define v0printf(fmt, ...) printf("pid=0x%x, %s(%d): " fmt, taskIdSelf(),\
|
||||
__FUNCTION__, __LINE__, ## __VA_ARGS__)
|
||||
|
||||
/** **/
|
||||
/** OS-specific implementation functions **/
|
||||
/** **/
|
||||
|
||||
/* memory allocation/de-allocation defines (OS-specific) */
|
||||
#define malloc_KERNEL(size) malloc(size)
|
||||
#define free_KERNEL(pointer) free(pointer)
|
||||
|
||||
#define strlen_KERNEL(str) strlen(str)
|
||||
|
||||
/* memory management routine defines (OS-specific) */
|
||||
#define memcpy_KERNEL(dest, src, size) bcopy((const char*) src, (char *) dest,\
|
||||
size)
|
||||
|
||||
/* OS-specific defines to transfer data from kernel domain to profileagent */
|
||||
#define copy_to_agent(dest, src, size) bcopy((const char*) src, (char*) dest,\
|
||||
size)
|
||||
|
||||
#define PROFILE_KERNEL_TID ((WIND_TCB *) -2)
|
||||
#define PROFILE_IDLE_TID ((WIND_TCB *) -3)
|
||||
|
||||
#define OSGetCurrentRegs(opi) ((REG_SET *) &(opi->activeThread->regs))
|
||||
#define OSGetCurrentTid(opi) ((int) opi->activeThread)
|
||||
#define OSGetCurrentTask(opi) OSGetCurrentTid(opi)
|
||||
#define OSGetCurrentEuid(opi) (0)
|
||||
/* #define OSIsAddrInKernel(addr, opi) (addr < (opi->sysMemTop)) */
|
||||
#define OSIsAddrInKernel(addr, opi) (RTI_FALSE)
|
||||
#define OSGetIrqPolicy() IRQ_ROUND_ROBIN
|
||||
|
||||
/** **/
|
||||
/** Unused OS-specific implementation functions **/
|
||||
/** **/
|
||||
|
||||
#define OSContextSwitch(x,y)
|
||||
#define OSThreadListLock()
|
||||
#define OSThreadListUnlock()
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptLock - lock task against preemption
|
||||
*
|
||||
* This routine locks the current task/thread against preemption by locking
|
||||
* out scheduling on the CPU of the task of interest. Scheduling on other
|
||||
* CPUs is unaffected.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptLock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
task_lock (&opi->preemptLock);
|
||||
/* no blocking calls after this point! */
|
||||
#else
|
||||
if (opi->irqSampling == RTI_TRUE) {
|
||||
lockKey = intLock();
|
||||
} else {
|
||||
taskLock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptUnlock - unlock task from preemption
|
||||
*
|
||||
* This routine unlocks the current task/thread from preemption.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptUnlock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
task_unlock (&opi->preemptLock);
|
||||
#else
|
||||
if (opi->irqSampling == RTI_TRUE) {
|
||||
intUnlock(lockKey);
|
||||
} else {
|
||||
taskUnlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptReadLock - lock task against writer preemption
|
||||
*
|
||||
* This routine locks the current task/thread against preemption by writers
|
||||
* by locking out scheduling on the CPU of the calling task and entering a
|
||||
* spin loop until read permission is granted. Scheduling on other CPUs is
|
||||
* unaffected.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptReadLock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskRDlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptLock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptReadUnlock - unlock task from writer preemption
|
||||
*
|
||||
* This routine unlocks the current task/thread from writer preemption.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptReadUnlock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskRDunlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptUnlock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptWriteLock - lock task against reader/writer preemption
|
||||
*
|
||||
* This routine locks the current task/thread against preemption by readers
|
||||
* and any other writer by locking out scheduling on the CPU of the calling
|
||||
* task and entering a spin loop until write permission is granted.
|
||||
* Scheduling on other CPUs is unaffected.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptWriteLock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskWRlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptLock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPreemptWriteUnlock - unlock task from reader/writer preemption
|
||||
*
|
||||
* This routine unlocks the current task/thread from reader/writer preemption.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSPreemptWriteUnlock (OSProfileInfo opi)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
taskWRunlock (&opi->taskRWLock);
|
||||
#else
|
||||
OSPreemptUnlock (opi);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetNumCPUs - get number of CPUs in system
|
||||
*
|
||||
* This routine returns the configured number of CPUs in the system.
|
||||
* NOTE: this number may not reflect the actual number of CPUs enabled!
|
||||
*
|
||||
* RETURNS: number of CPUs configured
|
||||
*/
|
||||
|
||||
static inline int OSGetNumCPUs (void)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
return (vxCpuConfiguredGet());
|
||||
#else
|
||||
return (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetCurrentPC - get the current task's PC
|
||||
*
|
||||
* This routine returns the current task/thread PC value.
|
||||
*
|
||||
* RETURNS: current thread/task PC value or 0xffffffff for untraced tasks
|
||||
*/
|
||||
|
||||
static inline unsigned long OSGetCurrentPC (OSProfileInfo opi)
|
||||
{
|
||||
if ((opi->activeThread == PROFILE_IDLE_TID) ||
|
||||
(opi->activeThread == PROFILE_KERNEL_TID))
|
||||
{
|
||||
return (0xffffffff);
|
||||
} else {
|
||||
return ((unsigned long) opi->activeThread->regs.reg_pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetCurrentCPU - get current CPU#
|
||||
*
|
||||
* This routine returns the index of the CPU on which the caller is running.
|
||||
*
|
||||
* CAVEAT: there is no guarantee that the CPU will not change prior to it's
|
||||
* return! It is the responsibility of the caller to ensure that scheduling
|
||||
* is suspended prior to calling this routine to ensure the returned index
|
||||
* is valid.
|
||||
*
|
||||
* INTERNAL
|
||||
* - ProfileScope supports profiling one CPU at a time on VxWorks.
|
||||
*
|
||||
* RETURNS: 0 to N-1, where N is the configured number of CPUs in the system.
|
||||
*/
|
||||
|
||||
static inline int OSGetCurrentCPU (void)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
return (vxCpuIndexGet());
|
||||
#else
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetSamplerTid - get task ID of task selected for sampling
|
||||
*
|
||||
* This routine returns the task ID of the task to be sampled.
|
||||
*
|
||||
* RETURNS: task ID of task to be sampled
|
||||
*/
|
||||
|
||||
static inline int OSGetSamplerTid (OSProfileInfo opi)
|
||||
{
|
||||
return (opi->samplerTid);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SMP_CONFIG
|
||||
|
||||
/**
|
||||
* localCpuTaskStateGet - get state of current task on local CPU
|
||||
*
|
||||
* Returns state of interrupted task on local CPU.
|
||||
*
|
||||
* RETURNS
|
||||
* TASK_LIB_CPU_HOLDS_SPINLOCK - task has a spin lock
|
||||
* TASK_LIB_CPU_HOLDS_KERNEL_LOCK - task has entered kernel and locked it
|
||||
* TASK_LIB_CPU_NO_INFO - task not in special state
|
||||
*
|
||||
* INTERNAL
|
||||
* This is a code segment taken directly from taskInfoByCpuGet().
|
||||
*/
|
||||
static __inline__
|
||||
int localCpuTaskStateGet (int cpuNum)
|
||||
{
|
||||
/*
|
||||
* It is never possible for a CPU to hold both a spinlock and the kernel
|
||||
* lock. This information could be changed out from under the caller, so
|
||||
* this has intentionally made an 'if, else if' block to avoid the
|
||||
* possibility of both TASK_LIB_CPU_HOLDS_SPINLOCK and
|
||||
* TASK_LIB_CPU_HOLDS_KERNEL_LOCK from being set.
|
||||
*/
|
||||
|
||||
if ((_WRS_KERNEL_CPU_GLOBAL_GET(cpuNum, spinLockIsrCnt) != 0) ||
|
||||
(_WRS_KERNEL_CPU_GLOBAL_GET(cpuNum, spinLockTaskCnt) != 0))
|
||||
{
|
||||
/* the CPU holds a spinlock, mark return value as such */
|
||||
|
||||
return TASK_LIB_CPU_HOLDS_SPINLOCK;
|
||||
}
|
||||
else if (KERNEL_LOCK_OWNER_GET() == cpuNum)
|
||||
{
|
||||
/* the CPU holds the kernel lock, mark return value as such */
|
||||
|
||||
return TASK_LIB_CPU_HOLDS_KERNEL_LOCK;
|
||||
}
|
||||
|
||||
return TASK_LIB_CPU_NO_INFO;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSCreateContext - record current context (TCB)
|
||||
*
|
||||
* This routine records the TCB ID and state of the current task/thread.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline RTIBool OSCreateContext (OSProfileInfo opi,
|
||||
unsigned int missedTicks)
|
||||
{
|
||||
int tid = taskIdSelf(); /* default task ID */
|
||||
#ifdef SMP_CONFIG
|
||||
atomic_t cpuIndex = vxCpuIndexGet();
|
||||
WIND_TCB * tcb = NULL;
|
||||
int stateInfo = localCpuTaskStateGet(cpuIndex);
|
||||
STATUS result = OK;
|
||||
unsigned int maxCpu = vxCpuConfiguredGet();
|
||||
|
||||
/* don't query our own CPU; we already know what task was running on it */
|
||||
if (opi->cpuNext != cpuIndex) {
|
||||
result = taskInfoByCpuGet (opi->cpuNext, &tid, &stateInfo);
|
||||
}
|
||||
tcb = taskTcb (tid);
|
||||
|
||||
/* set next and current victim CPU indices */
|
||||
cpuIndex = opi->cpuNext + 1;
|
||||
if (cpuIndex >= maxCpu) cpuIndex = 0;
|
||||
vxAtomicSet (&opi->cpuCurrent, opi->cpuNext);
|
||||
vxAtomicSet (&opi->cpuNext, cpuIndex);
|
||||
|
||||
/* If bogus CPU or sampler task ID, just return */
|
||||
if ((result == ERROR) || (OSGetSamplerTid (opi) == tid)) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
/* If idle task encountered, don't trace it, just record it.
|
||||
* Only a system idle task can have priority 287.
|
||||
*/
|
||||
if ((tid == 0) || (tcb == NULL) || (tcb->priority == 287)) {
|
||||
opi->activeThread = PROFILE_IDLE_TID;
|
||||
}
|
||||
|
||||
/* If kernel state task, don't trace it,
|
||||
* just record it and allow task to continue.
|
||||
*/
|
||||
else if ((stateInfo == TASK_LIB_CPU_HOLDS_KERNEL_LOCK) ||
|
||||
(KERNEL_ENTERED_ME()))
|
||||
{
|
||||
opi->activeThread = PROFILE_KERNEL_TID;
|
||||
}
|
||||
|
||||
/* If task holds a spinlock, we trace it immediately
|
||||
* after it releases the lock and continues.
|
||||
* TD: Add support for weighting sample by time spent in spinlock!
|
||||
* Add SPIN_LOCK entity?
|
||||
* else {
|
||||
* if (stateInfo == TASK_LIB_CPU_HOLDS_SPINLOCK) {
|
||||
* opi->pentity = SPIN_LOCK;
|
||||
* }
|
||||
* opi->activeThread = tcb;
|
||||
* ...
|
||||
*/
|
||||
|
||||
/* Set ID of task to sample and start tick timer
|
||||
* to record any time spent in a spinlock.
|
||||
*/
|
||||
else {
|
||||
opi->activeThread = tcb;
|
||||
opi->spinTicks = missedTicks;
|
||||
}
|
||||
#else
|
||||
if (kernelIsIdle) {
|
||||
opi->activeThread = PROFILE_IDLE_TID;
|
||||
} else if (kernelState || (taskIdCurrent == NULL)) {
|
||||
opi->activeThread = PROFILE_KERNEL_TID;
|
||||
} else if (OSGetSamplerTid (opi) != tid) {
|
||||
opi->activeThread = taskIdCurrent;
|
||||
opi->spinTicks = missedTicks;
|
||||
} else {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSRunSamplerThread - trigger execution of the sampler task
|
||||
*
|
||||
* This routine triggers execution of the sampler task.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSRunSamplerThread (OSProfileInfo opi)
|
||||
{
|
||||
(void)semGive(opi->sem);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSWaitSamplerThread - wait for trigger to start sampling
|
||||
*
|
||||
* This routine waits for the trigger to start the sampler task.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
static inline void OSWaitSamplerThread (OSProfileInfo opi)
|
||||
{
|
||||
(void)semTake(opi->sem, WAIT_FOREVER);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSFindThread - determine if thread/task to be sampled was found
|
||||
*
|
||||
* This routine determines if a task/thread was found for the sampler task.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if task found, else, RTI_FALSE
|
||||
*/
|
||||
|
||||
static inline RTIBool OSFindThread (int tid, OSProfileInfo opi)
|
||||
{
|
||||
if (tid == opi->samplerTid) {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
opi->activeThread = taskTcb(tid);
|
||||
|
||||
if (opi->activeThread == NULL) {
|
||||
return (RTI_FALSE);
|
||||
} else {
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSPopulateMsgStruct - populate profile message structure by task type
|
||||
*
|
||||
* This routine populates the message structure to be sent to the host and
|
||||
* returns a boolean indicating whether the task was a special case or not.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if idle or kernel task, else, RTI_FALSE
|
||||
*/
|
||||
|
||||
static inline RTIBool OSPopulateMsgStruct (OSProfileInfo opi, ProfileMsg msg,
|
||||
RTIBool systemMode)
|
||||
{
|
||||
RTIBool ret = RTI_FALSE;
|
||||
|
||||
/* if kernel is running idle */
|
||||
if (opi->activeThread == PROFILE_IDLE_TID) {
|
||||
msg->pentity = IDLE_THREAD;
|
||||
msg->pid = (int) KERNEL_ID;
|
||||
msg->numSamples = 0;
|
||||
ret = RTI_TRUE;
|
||||
} else if (opi->activeThread == PROFILE_KERNEL_TID) {
|
||||
msg->pentity = KERNEL_STATE;
|
||||
msg->pid = (int) KERNEL_ID;
|
||||
msg->numSamples = 0;
|
||||
ret = RTI_TRUE;
|
||||
} else {
|
||||
if (RTP_ID_OF_TASK(opi->activeThread) == KERNEL_ID) {
|
||||
msg->pentity = KERNEL_THREAD;
|
||||
} else {
|
||||
/* for now, if we come across an RTP thread, we dont
|
||||
context trace that thread. */
|
||||
msg->pentity = USER_THREAD;
|
||||
}
|
||||
msg->pid = (int) RTP_ID_OF_TASK(opi->activeThread);
|
||||
}
|
||||
msg->tid = (int) opi->activeThread;
|
||||
#ifdef SMP_CONFIG
|
||||
msg->cpuid = opi->cpuCurrent;
|
||||
#else
|
||||
msg->cpuid = 0;
|
||||
#endif
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#pragma end_Package
|
||||
|
||||
#define PROFILE_SAMPLER_NAME "tProfileSampler"
|
||||
|
||||
/* extern void ProfileRunSamplerThread(void* data); */
|
||||
|
||||
Private
|
||||
/******************************************************************************
|
||||
************************** INTERRUPT CONTEXT **********************************
|
||||
*******************************************************************************
|
||||
*
|
||||
* OSProfileSampleSysClk - handle system clock tick interrupt
|
||||
*
|
||||
* This routine handles the system clock tick interrupt by triggering the
|
||||
* sampler task.
|
||||
*
|
||||
* RETURNS: 0 always
|
||||
*
|
||||
* INTERNAL: the usrClock() routine is a VxWorks funtion used to announce the
|
||||
* system clock tick to the kernel and MUST be called. It is found in
|
||||
* vxworks-6.x/target/config/all/usrConfig.c.
|
||||
*/
|
||||
|
||||
int OSProfileSampleSysClk (ProfileInfo pi)
|
||||
{
|
||||
usrClock();
|
||||
ProfileSample (pi);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSThreadExists - validate task existence
|
||||
*
|
||||
* This routine validates the task ID of the task to be sampled.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if valid task ID, else, RTI_FALSE
|
||||
*/
|
||||
|
||||
RTIBool OSThreadExists (int tid)
|
||||
{
|
||||
if (taskIdVerify (tid) == OK) {
|
||||
return (RTI_TRUE);
|
||||
} else {
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileSetMode - set sampling mode
|
||||
*
|
||||
* This routine sets the sampling mode (IRQ or not) and starts the sampler
|
||||
* task if IRQs are not to be sampled. If IRQs are to be sampled and a
|
||||
* sampler task is already running, the sampler task is deleted. (Sampling
|
||||
* is not done by a sampler task when sampling IRQ state.)
|
||||
*
|
||||
* RETURNS: RTI_TRUE if mode set, else, RTI_FALSE if sampler task spawn failed
|
||||
*/
|
||||
|
||||
RTIBool OSProfileSetMode (void* data, RTIBool irqSampling, OSProfileInfo opi)
|
||||
{
|
||||
opi->irqSampling = irqSampling;
|
||||
|
||||
#ifdef SMP_CONFIG
|
||||
/* Initialize the CPU# used for sampling */
|
||||
opi->cpuCurrent = opi->cpuNext = vxCpuIndexGet ();
|
||||
#endif
|
||||
|
||||
/* if sampler thread doesn't exist, create it */
|
||||
if ((irqSampling == RTI_FALSE) &&
|
||||
(taskNameToId (PROFILE_SAMPLER_NAME) == ERROR))
|
||||
{
|
||||
opi->samplerTid = taskSpawn (PROFILE_SAMPLER_NAME, 0, 0, 16384,
|
||||
(FUNCPTR) ProfileRunSamplerThread,
|
||||
(int) data, 0,0,0,0,0,0,0,0,0);
|
||||
if (opi->samplerTid == TASK_ID_ERROR) {
|
||||
v0printf ("OSProfileModeSet: Can't create sampler task %s!\n",
|
||||
PROFILE_SAMPLER_NAME);
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* If sampler thread is running and IRQ sampling is selected,
|
||||
* delete the thread. Since this function call is protected by
|
||||
* OS thread locking, sampler thread will be waiting on semaphore
|
||||
* and, hence, safe to delete.
|
||||
*/
|
||||
else if ((irqSampling == RTI_TRUE) &&
|
||||
(taskNameToId (PROFILE_SAMPLER_NAME) == OK))
|
||||
{
|
||||
taskDelete (opi->samplerTid);
|
||||
opi->samplerTid = 0;
|
||||
}
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileKill - done profiling, kill tool
|
||||
*
|
||||
* This routine kills the sampler task and cleans up prior to exiting.
|
||||
*
|
||||
* RETURNS: RTI_TRUE on success
|
||||
*/
|
||||
|
||||
RTIBool OSProfileKill (OSProfileInfo opi)
|
||||
{
|
||||
if (opi == NULL) {
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
if (opi->samplerTid != 0) {
|
||||
taskDelete (opi->samplerTid);
|
||||
opi->samplerTid = 0;
|
||||
}
|
||||
opi->irqSampling = RTI_FALSE;
|
||||
opi->activeThread = 0;
|
||||
|
||||
ST_context_uninit ();
|
||||
|
||||
#ifdef SMP_CONFIG
|
||||
rw_lock_done (&opi->taskRWLock);
|
||||
task_lock_done (&opi->preemptLock);
|
||||
#endif
|
||||
|
||||
if (opi->sem != 0) {
|
||||
(void)semDelete (opi->sem);
|
||||
opi->sem = 0;
|
||||
}
|
||||
free_KERNEL (opi);
|
||||
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileConnectClk - connect profiler to a clock
|
||||
*
|
||||
* This routine connects the profiler to a system clock tick interrupt handler
|
||||
* list. Either an auxilliary clock, if available, or the system clock is used.
|
||||
*
|
||||
* RETURNS: RTI_TRUE (OK) if connected, else, RTI_FALSE (ERROR) if connect
|
||||
* failed
|
||||
*/
|
||||
|
||||
RTIBool OSProfileConnectClk (void* data, char* clock)
|
||||
{
|
||||
if (strcmp (clock, SYS_CLK) == 0) {
|
||||
return (RTIClkConnect ((CLKFUNC)OSProfileSampleSysClk, data, clock));
|
||||
} else {
|
||||
return (RTIClkConnect ((CLKFUNC)ProfileSample, data, clock));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileSetSampleRate - set sampler clock frequency of aux clock
|
||||
*
|
||||
* This routine attempts to set the frequency of the auxilliary clock if it
|
||||
* is used for sampling. The actual frequency set is returned, for either
|
||||
* the auxilliary or system clock, which ever is used for sampling.
|
||||
*
|
||||
* RETURNS: actual sampler clock frequency
|
||||
*/
|
||||
|
||||
int OSProfileSetSampleRate (int requestedSR, char* clock)
|
||||
{
|
||||
int rate;
|
||||
|
||||
if (strcmp (clock, AUX_CLK) == 0) {
|
||||
rate = RTIClkRateSet (requestedSR, clock);
|
||||
} else {
|
||||
rate = RTIClkRateGet (clock);
|
||||
}
|
||||
return (rate);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProfileInit - initialize the profiler
|
||||
*
|
||||
* This routine initializes the profiler.
|
||||
*
|
||||
* INTERNAL: currently this routine just allocates a profiler structure
|
||||
* instance.
|
||||
*
|
||||
* RETURNS: the OSProfileInfoStorage structure pointer or NULL on failure
|
||||
*/
|
||||
|
||||
OSProfileInfo OSProfileInit (RTIBool irqSampling)
|
||||
{
|
||||
OSProfileInfo opi = (OSProfileInfo)
|
||||
malloc_KERNEL (sizeof(struct OSProfileInfoStorage));
|
||||
if (opi == NULL) {
|
||||
v0printf ("OSProfileInit: Can't allocate OSProfileInfo!\n");
|
||||
} else {
|
||||
#ifdef SMP_CONFIG
|
||||
if (!rw_lock_init (&opi->taskRWLock)) {
|
||||
free (opi);
|
||||
opi = NULL;
|
||||
}
|
||||
else if (!task_lock_init (&opi->preemptLock)) {
|
||||
rw_lock_done(&opi->taskRWLock);
|
||||
free (opi);
|
||||
opi = NULL;
|
||||
} else {
|
||||
#endif
|
||||
opi->irqSampling = RTI_FALSE;
|
||||
opi->activeThread = 0;
|
||||
opi->sem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
|
||||
opi->sysMemTop = (unsigned long) sysMemTop();
|
||||
opi->samplerTid = 0;
|
||||
#ifdef SMP_CONFIG
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return (opi);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSProcessSamples - process profiler samples
|
||||
*
|
||||
* This routine is not required for VxWorks.
|
||||
*
|
||||
* RETURNS: n/a
|
||||
*/
|
||||
|
||||
void OSProcessSamples (void* buffer, int size, OSProfileInfo opi)
|
||||
{
|
||||
/* no-op for VxWorks */
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* profile_arch.h - Header file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Header file.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
/* defines */
|
||||
#ifndef _PROFILE_ARCH_H_
|
||||
#define _PROFILE_ARCH_H_
|
||||
|
||||
#ifdef CPU_FAMILY
|
||||
|
||||
|
||||
#endif /* CPU_FAMILY */
|
||||
|
||||
|
||||
#endif /* _PROFILE_ARCH_H_ */
|
||||
@@ -0,0 +1,32 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../..
|
||||
|
||||
vpath %.c $(CURDIR)/vx
|
||||
LIB_BASE_NAME = profile
|
||||
|
||||
EXTRA_DEFINE += -DSCOPEPROFILEVERSION=\"4.11a\" -DRTI_VXWORKS_TGT
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include/vx \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/context \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include \
|
||||
-I../include
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= main.o wtxcalls.o communications.o tcpOut.o fileOut.o
|
||||
|
||||
PKG_H = fileOut.pkg.h tcpOut.pkg.h communications.pkg.h wtxcalls.pkg.h \
|
||||
main.pkg.h
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
@@ -0,0 +1,611 @@
|
||||
/* communications.c - ProfileScope Communications Support */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003-2009, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01b,12oct13,wzc Fix prevent warnings.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
4.4,12aug03,avd Written
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
ProfileScope Communications Support
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "targetAgent.h"
|
||||
|
||||
#include <stdlib.h> /* for strtoul(),atoi(), and free() */
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <eventsxml.h> /* for XML callbacks */
|
||||
|
||||
#if defined(RTI_LINUX_TGT)
|
||||
# include "linux/profile_arch.h"
|
||||
# include <rtitools/rtitools_linuxutils.h>
|
||||
#endif /* if defined(RTI_LINUX_TGT) */
|
||||
|
||||
#include "tcpOut.pkg.h"
|
||||
#include "main.pkg.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#if defined(RTI_WIN32)
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ARRAY_TID = 0,
|
||||
ARRAY_UID,
|
||||
ARRAY_CPU
|
||||
} eType;
|
||||
|
||||
|
||||
Private
|
||||
int GetArray(char* echar, unsigned int* eval, eType type)
|
||||
{
|
||||
char * token;
|
||||
char * pStart = echar;
|
||||
int i = 0;
|
||||
|
||||
#if defined(RTI_WIN32)
|
||||
// TD: when we move to msvc++ 2005, we can probably use strtok_s() instead
|
||||
token = strtok(echar, " ");
|
||||
#else
|
||||
token = strtok_r(echar, " ", &pStart);
|
||||
#endif
|
||||
|
||||
while (token != 0) {
|
||||
if (type == ARRAY_UID) {
|
||||
eval[i++] = OSGetUserId(token);
|
||||
} else {
|
||||
eval[i++] = strtoul(token, NULL, 0);
|
||||
}
|
||||
#if defined(RTI_WIN32)
|
||||
token = strtok(NULL, " ");
|
||||
#else
|
||||
token = strtok_r(NULL, " ", &pStart);
|
||||
#endif
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
int GetSize(const char* const echar)
|
||||
{
|
||||
int i = 0, size = 1;
|
||||
if (echar == NULL)
|
||||
return 0;
|
||||
while (echar[i] != '\0') {
|
||||
if (echar[i++] == ' ')
|
||||
size++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
* COMMAND CALLBACKS
|
||||
*****************************/
|
||||
|
||||
Package
|
||||
void ProfileInitCmd(const void * xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
|
||||
char* clock = parseParamString("clock", xmlEngine);
|
||||
char* tids = parseParamString("tids", xmlEngine);
|
||||
RTIBool irqSampling = (RTIBool)
|
||||
atoi(parseParamString("irqSampling", xmlEngine));
|
||||
unsigned int sampleRate = atoi(parseParamString("sampleRate", xmlEngine));
|
||||
unsigned int maxSamples = atoi(parseParamString("maxSamples", xmlEngine));
|
||||
unsigned int maxStack = atoi(parseParamString("maxStack", xmlEngine));
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
ProfileInfo pi = 0;
|
||||
RTIBool retval = RTI_FALSE;
|
||||
unsigned int* eval;
|
||||
int size;
|
||||
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileInitCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
v1printf("Received ProfileInit: clock=%s tids=%s irqSampling=%d "
|
||||
"sampleRate=%d maxSamples=%u maxStack=%u.\n",
|
||||
clock, tids, irqSampling, sampleRate, maxSamples, maxStack);
|
||||
|
||||
eval = (unsigned int*) malloc(sizeof(unsigned int)*GetSize(tids));
|
||||
if (eval != 0) {
|
||||
pi = ProfileInit(clock, eval, GetArray(tids, eval, ARRAY_TID),
|
||||
irqSampling, sampleRate, maxSamples, maxStack,
|
||||
link->xmlEngine);
|
||||
if (pi == NULL) {
|
||||
retval = RTI_TRUE;
|
||||
}
|
||||
free(eval);
|
||||
} else {
|
||||
v0printf("malloc FAILED in Profile in\n");
|
||||
return;
|
||||
}
|
||||
|
||||
SetProfileInfo(pi);
|
||||
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">", retval);
|
||||
TcpConnectionSendData(link, response, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileKillCmd(const void * xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
RTIBool retval;
|
||||
int size;
|
||||
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileKillCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
retval = ProfileKill(GetProfileInfo(), link->xmlEngine);
|
||||
|
||||
v1printf("Received ProfileKill.\n");
|
||||
if (retval) {
|
||||
SetProfileInfo(0);
|
||||
}
|
||||
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">", retval);
|
||||
TcpConnectionSendData(link, response, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileFreezeCmd(const void * xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
unsigned int freeze = atoi(parseParamString("freeze", xmlEngine));
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
int size;
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileFreezeCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
v1printf("Received ProfileFreeze: %d\n", freeze);
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">", ProfileFreeze((RTIBool) freeze,
|
||||
GetProfileInfo(),
|
||||
link->xmlEngine));
|
||||
TcpConnectionSendData(link, response, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileClearCmd(const void * xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
int size;
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileClearCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
v1printf("Received ProfileClear.\n");
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">", ProfileClear(GetProfileInfo(),
|
||||
link->xmlEngine));
|
||||
TcpConnectionSendData(link, response, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileSetModeCmd(const void * xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
char* tids = parseParamString("tids", xmlEngine);
|
||||
RTIBool irqSampling = (RTIBool)
|
||||
atoi(parseParamString("irqSampling", xmlEngine));
|
||||
RTIBool dontClear = (RTIBool)
|
||||
atoi(parseParamString("dontClear", xmlEngine));
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
unsigned int* eval;
|
||||
int size;
|
||||
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileSetModeCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
v1printf("Received ProfileSetMode: tids=%s irqSampling=%d dontClear=%d\n",
|
||||
tids, irqSampling, dontClear);
|
||||
eval = (unsigned int*) malloc(sizeof(unsigned int)*GetSize(tids));
|
||||
if (eval == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">",
|
||||
ProfileSetMode(eval, GetArray(tids, eval, ARRAY_TID),
|
||||
irqSampling, dontClear,
|
||||
GetProfileInfo(), link->xmlEngine));
|
||||
TcpConnectionSendData(link, response, size);
|
||||
free(eval);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileSetSampleRateCmd(const void * xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
unsigned int sampleRate = atoi(parseParamString("sampleRate", xmlEngine));
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
int size;
|
||||
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileSetSampleRateCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
v1printf("Received ProfileSetSampleRate: sampleRate=%d.\n", sampleRate);
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">",
|
||||
ProfileSetSampleRate(sampleRate, GetProfileInfo(),
|
||||
link->xmlEngine));
|
||||
TcpConnectionSendData(link, response, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileConnectClkCmd(const void* xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
char* clock = parseParamString("clock", xmlEngine);
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
int size;
|
||||
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileConnectClkCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
v1printf("Received ProfileConnectClk: clock=%s.\n", clock);
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">",
|
||||
ProfileConnectClk(clock, GetProfileInfo(),
|
||||
link->xmlEngine));
|
||||
TcpConnectionSendData(link, response, size);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileShutdownCmd(const void* xmlEngine)
|
||||
{
|
||||
v1printf("Received ProfileShutdown.\n");
|
||||
ProfileScopeShutdown();
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileGetStatusCmd(const void *xmlEngine)
|
||||
{
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileGetStatusCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
v1printf("Received ProfileGetStatus.\n");
|
||||
GetProfileStatus((void*) link, GetProfileInfo());
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileSetIgnoreCmd(const void *xmlEngine)
|
||||
{
|
||||
char response[256];
|
||||
int maxnum;
|
||||
char* user = parseParamString("user", xmlEngine);
|
||||
char* tid = parseParamString("tid", xmlEngine);
|
||||
char* cpu = parseParamString("cpu", xmlEngine);
|
||||
RTIBool retval = RTI_TRUE;
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
int size = 0;
|
||||
unsigned int * eval;
|
||||
|
||||
if (link == NULL) {
|
||||
v0printf("ProfileSetIgnoreCmd parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
v1printf("Received ProfileSetIgnore: user=%s tid=%s cpu=%s.\n",
|
||||
user, tid, cpu);
|
||||
maxnum = GetSize(tid);
|
||||
if (GetSize(user) > maxnum)
|
||||
maxnum = GetSize(user);
|
||||
if (GetSize(cpu) > maxnum)
|
||||
maxnum = GetSize(cpu);
|
||||
|
||||
eval = (unsigned int*) malloc(sizeof(unsigned int)*maxnum);
|
||||
if (!eval) {
|
||||
printf("Failed to allocate memory for eval array.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size = GetArray(user, eval, ARRAY_UID);
|
||||
if (ProfileSetIgnore(eval, size, IGNORE_UID, GetProfileInfo(),
|
||||
link->xmlEngine)
|
||||
== RTI_FALSE) {
|
||||
retval = RTI_FALSE;
|
||||
}
|
||||
|
||||
size = GetArray(tid, eval, ARRAY_TID);
|
||||
if (ProfileSetIgnore(eval, size, IGNORE_TID, GetProfileInfo(),
|
||||
link->xmlEngine)
|
||||
== RTI_FALSE) {
|
||||
retval = RTI_FALSE;
|
||||
}
|
||||
|
||||
size = GetArray(cpu, eval, ARRAY_CPU);
|
||||
if (ProfileSetIgnore(eval, size, IGNORE_CPU, GetProfileInfo(),
|
||||
link->xmlEngine)
|
||||
== RTI_FALSE) {
|
||||
retval = RTI_FALSE;
|
||||
}
|
||||
|
||||
size = snprintf(response, 256, "<" PROFILE_RPCRETURN " retval=\"%d\"></"
|
||||
PROFILE_RPCRETURN ">", retval);
|
||||
TcpConnectionSendData(link, response, size);
|
||||
free(eval);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void pingCommand(const void * xmlEngine)
|
||||
{
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
if (link == NULL) {
|
||||
v0printf("pingCommand parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TcpConnectionSendData(link, "<ping></ping>", 13);
|
||||
}
|
||||
|
||||
|
||||
#if defined(RTI_LINUX_TGT)
|
||||
|
||||
Package
|
||||
/**
|
||||
* Handle the host's response to our initial symbol query. Note that the
|
||||
* order of parsing is dictated by the SendSymbolRequestMsg() function in
|
||||
* linux/main.c; these two routines need to stay in lockstep.
|
||||
*/
|
||||
void symbol_query_responseCommand(const void * xmlEngine)
|
||||
{
|
||||
char * address_list = parseParamString("addresses", xmlEngine);
|
||||
char * trav = address_list;
|
||||
unsigned int i;
|
||||
bool smpKernel = false;
|
||||
|
||||
/* now parse the addresses out from the required symbol list */
|
||||
errno = 0;
|
||||
for (i = 0; ArchSymbols[i].name != 0; ++i) {
|
||||
ArchSymbols[i].address = (void *) strtoul(trav, &trav, 16);
|
||||
if ( (ULONG_MAX == (unsigned long) ArchSymbols[i].address)
|
||||
&& (errno != 0) )
|
||||
{
|
||||
printf("Error parsing symbol query response from host:\n\t"
|
||||
"%s\n%s\n", strerror(errno), address_list);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* now look for symbols needed for SMP support */
|
||||
ArchSMPSymbols[0].address = (void *) strtoul(trav, &trav, 16);
|
||||
if ( (ULONG_MAX == (unsigned long) ArchSymbols[i].address)
|
||||
&& (errno != 0) )
|
||||
{
|
||||
printf("Error parsing symbol query response from host:\n\t"
|
||||
"%s\n%s\n", strerror(errno), address_list);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ArchSMPSymbols[0].address != 0) {
|
||||
smpKernel = true;
|
||||
}
|
||||
|
||||
/* we need to parse these out even if the target isn't SMP, to advance
|
||||
the read pointer */
|
||||
for (i = 0; ArchSMPSymbols[i].name != 0; ++i) {
|
||||
ArchSMPSymbols[i].address = (void *) strtoul(trav, &trav, 16);
|
||||
if ( (ULONG_MAX == (unsigned long) ArchSMPSymbols[i].address)
|
||||
&& (errno != 0) )
|
||||
{
|
||||
printf("Error parsing symbol query response from host:\n\t"
|
||||
"%s\n%s\n", strerror(errno), address_list);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* determine whether this board supports a generic timer interface */
|
||||
for (i = 0; 0 != TargetAgent.ST_clock_api->required_symbols[i].name; ++i)
|
||||
{
|
||||
void * address = (void *) strtoul(trav, &trav, 16);
|
||||
if ( (ULONG_MAX == (unsigned long) address)
|
||||
&& (errno != 0) )
|
||||
{
|
||||
printf("Error parsing symbol query response from host:\n\t"
|
||||
"%s\n%s\n", strerror(errno), address_list);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (0 == address) {
|
||||
TargetAgent.supports_generic_timers = false;
|
||||
}
|
||||
TargetAgent.ST_clock_api->required_symbols[i].address = address;
|
||||
} /* for each timer api symbol */
|
||||
|
||||
/* parse board-specific timer symbols */
|
||||
for (i = 0; 0 != ArchBoardTimerRoutines[i]; ++i)
|
||||
{
|
||||
unsigned int j;
|
||||
void * address;
|
||||
|
||||
/* try and locate all the symbols required for this timer */
|
||||
for (j = 0; 0 != ArchBoardTimerRoutines[i]->required_symbols[j].name;
|
||||
++j)
|
||||
{
|
||||
address = (void *) strtoul(trav, &trav, 16);
|
||||
if ( (ULONG_MAX == (unsigned long) address)
|
||||
&& (errno != 0) )
|
||||
{
|
||||
printf("Error parsing symbol query response from host:\n\t"
|
||||
"%s\n%s\n", strerror(errno), address_list);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ArchBoardTimerRoutines[i]->required_symbols[j].address = address;
|
||||
} /* for each symbol in a timer */
|
||||
} /* for each timer */
|
||||
|
||||
if (!TargetAgentInit("profileModule.ko", smpKernel)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
TargetAgent.waiting_for_symbols = false;
|
||||
return;
|
||||
|
||||
fail:
|
||||
/* had a critical failure, trigger a target agent shutdown */
|
||||
TargetAgent.shouldStop = true;
|
||||
TargetAgent.waiting_for_symbols = false;
|
||||
}
|
||||
|
||||
|
||||
/* length of a message that contains 100 symbol records */
|
||||
#define MOD_SYM_MSG (100 * (4 + KSYM_NAME_LEN + MODULE_NAME_LEN))
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Handle a request for kernel module symbols. Sends back all of the text
|
||||
* symbols for any currently loaded kernel modules.
|
||||
*/
|
||||
void kernel_module_symbolsCommand(const void * xmlEngine)
|
||||
{
|
||||
TcpLink * link = getLinkFromCallback(xmlEngine);
|
||||
char buf[MOD_SYM_MSG];
|
||||
int size;
|
||||
unsigned int i, j;
|
||||
int num_symbols;
|
||||
ksym_entry_t * symbols;
|
||||
|
||||
if (link == NULL) {
|
||||
v0printf("kernel_module_symbolsCommand parameters error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
num_symbols = readKernelSymbols(&symbols);
|
||||
|
||||
if (num_symbols <= 0) {
|
||||
TcpConnectionSendData(link,
|
||||
"<Kernel_Module_Symbols_Response kernel_symbols=\"\"></Kernel_Module_Symbols_Response>", 83);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send header */
|
||||
size = snprintf(buf, MOD_SYM_MSG,
|
||||
"<Kernel_Module_Symbols_Response kernel_symbols=\"");
|
||||
|
||||
TcpConnectionSendData(link, buf, size);
|
||||
|
||||
/* send modules, 100 at a time */
|
||||
j = 0;
|
||||
size = 0;
|
||||
for (i = 0; i < num_symbols; ++i) {
|
||||
#if defined(RTI_LINUX26)
|
||||
/* only send if it's a module text symbol */
|
||||
if ( (symbols[i].module[0] != 0)
|
||||
&& ((symbols[i].type == 'T') || (symbols[i].type == 't')) )
|
||||
#else
|
||||
/* only send if it's a module symbol */
|
||||
if (symbols[i].module[0] != 0)
|
||||
#endif
|
||||
{
|
||||
size += snprintf(buf + size, MOD_SYM_MSG - size,
|
||||
"%lx %s %s ",
|
||||
(unsigned long) symbols[i].address,
|
||||
symbols[i].name, symbols[i].module);
|
||||
if (size >= MOD_SYM_MSG) {
|
||||
/* message overflow */
|
||||
printf("Overflow sending kernel module symbols, please contact support@windriver.com\n");
|
||||
|
||||
free(symbols);
|
||||
return;
|
||||
}
|
||||
|
||||
/* send the message if it's full */
|
||||
if (100 == j) {
|
||||
TcpConnectionSendData(link, buf, size);
|
||||
size = 0;
|
||||
j = 0;
|
||||
} else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(symbols);
|
||||
|
||||
/* send any leftovers that didn't make it into a full message */
|
||||
if (j > 0) {
|
||||
/* remove the trailing space */
|
||||
--size;
|
||||
TcpConnectionSendData(link, buf, size);
|
||||
size = 0;
|
||||
}
|
||||
|
||||
size = snprintf(buf, MOD_SYM_MSG,
|
||||
"\"></Kernel_Module_Symbols_Response>");
|
||||
TcpConnectionSendData(link, buf, size);
|
||||
}
|
||||
|
||||
#endif /* if defined(RTI_LINUX_TGT) */
|
||||
|
||||
|
||||
Package
|
||||
const CommandIdentifier Commands[NUM_LINK_COMMANDS] = {
|
||||
#if defined(RTI_LINUX_TGT)
|
||||
{"Symbol_query_response", symbol_query_responseCommand},
|
||||
{"Kernel_Module_Symbols", kernel_module_symbolsCommand},
|
||||
#endif /* if defined(RTI_LINUX_TGT) */
|
||||
{"Init", ProfileInitCmd},
|
||||
{"Kill", ProfileKillCmd},
|
||||
{"Freeze", ProfileFreezeCmd},
|
||||
{"Clear", ProfileClearCmd},
|
||||
{"SetMode", ProfileSetModeCmd},
|
||||
{"SetSampleRate", ProfileSetSampleRateCmd},
|
||||
{"ConnectClk", ProfileConnectClkCmd},
|
||||
{"Shutdown", ProfileShutdownCmd},
|
||||
{"GetStatus", ProfileGetStatusCmd},
|
||||
{"Ignore", ProfileSetIgnoreCmd},
|
||||
{"ping", pingCommand}
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/* communications.pkg.h - built from: communications.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef communications_pkg_h
|
||||
#define communications_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern void ProfileInitCmd(const void * xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileKillCmd(const void * xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileFreezeCmd(const void * xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileClearCmd(const void * xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileSetModeCmd(const void * xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileSetSampleRateCmd(const void * xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileConnectClkCmd(const void* xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileShutdownCmd(const void* xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileGetStatusCmd(const void *xmlEngine);
|
||||
|
||||
|
||||
extern void ProfileSetIgnoreCmd(const void *xmlEngine);
|
||||
|
||||
|
||||
extern void pingCommand(const void * xmlEngine);
|
||||
|
||||
|
||||
/**
|
||||
* Handle the host's response to our initial symbol query. Note that the
|
||||
* order of parsing is dictated by the SendSymbolRequestMsg() function in
|
||||
* linux/main.c; these two routines need to stay in lockstep.
|
||||
*/
|
||||
extern void symbol_query_responseCommand(const void * xmlEngine);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a request for kernel module symbols. Sends back all of the text
|
||||
* symbols for any currently loaded kernel modules.
|
||||
*/
|
||||
extern void kernel_module_symbolsCommand(const void * xmlEngine);
|
||||
|
||||
|
||||
extern const CommandIdentifier Commands[NUM_LINK_COMMANDS];
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* communications_pkg_h */
|
||||
@@ -0,0 +1,71 @@
|
||||
/* fileOut.c - File operation */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
File operation
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "targetAgent.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
|
||||
Package
|
||||
RTIBool OutputFileOpen(OutputFile * const f,
|
||||
const char * const filename)
|
||||
{
|
||||
f->fd = fopen(filename, "rw+");
|
||||
|
||||
if ( f->fd == NULL ) {
|
||||
printf("FILENAME: %s\n", filename);
|
||||
perror("error opening output file");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* seek to end of file before writing */
|
||||
if (fseek(f->fd, 0, SEEK_END) == -1) {
|
||||
perror("Couldn't seek to end of file");
|
||||
}
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
RTIBool OutputFileSendData(const OutputFile * const f,
|
||||
const char * data,
|
||||
const unsigned int size)
|
||||
{
|
||||
if (fwrite(data, sizeof(size), size, f->fd) != size) {
|
||||
perror("Failed to write output to file");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
Package
|
||||
void OutputFileClose(const OutputFile * const f)
|
||||
{
|
||||
if (f->fd != NULL) {
|
||||
fclose(f->fd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/* fileOut.pkg.h - built from: fileOut.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef fileOut_pkg_h
|
||||
#define fileOut_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern RTIBool OutputFileOpen(OutputFile * const f,
|
||||
const char * const filename);
|
||||
|
||||
|
||||
extern RTIBool OutputFileSendData(const OutputFile * const f,
|
||||
const char * data,
|
||||
const unsigned int size);
|
||||
|
||||
|
||||
extern void OutputFileClose(const OutputFile * const f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* fileOut_pkg_h */
|
||||
@@ -0,0 +1,50 @@
|
||||
/* main.pkg.h - built from: /view/ot.40_RCPL8.2024030303/vobs/rtca/component_roots/comp_rtca/target/src/profile/targetAgent/vx/main.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef main_pkg_h
|
||||
#define main_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern unsigned int PROFILESCOPE_LIB_VERSION;
|
||||
|
||||
|
||||
extern void GetProfileStatus(void* link, ProfileInfo pi);
|
||||
|
||||
|
||||
extern ProfileInfo GetProfileInfo(void);
|
||||
|
||||
|
||||
extern void SetProfileInfo(ProfileInfo pi);
|
||||
|
||||
|
||||
extern void ProfileScopeShutdown(void);
|
||||
|
||||
extern void ProfileScopeShutdownInternal(void);
|
||||
|
||||
|
||||
extern int ProfileScopeAgentVersionGet(void);
|
||||
|
||||
|
||||
extern int ProfileScopeInit (int verbosity,
|
||||
int pollrate,
|
||||
int linkPriority,
|
||||
int port,
|
||||
RTIBool wtxMode,
|
||||
char * file,
|
||||
void * textStartAdrs,
|
||||
void * textEndAdrs,
|
||||
unsigned long wtxLink);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* main_pkg_h */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* targetAgent.h - Target Agent header file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Target Agent header file.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h> /* for FILE typedef */
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <rtilib/rti_time.h>
|
||||
#include <rtilib/rti_tcp.h>
|
||||
|
||||
#if defined(RTI_LINUX_TGT)
|
||||
#include "profile_linux.h"
|
||||
#elif defined(RTI_VXWORKS_TGT) || defined(RTI_VXWORKS_HOST)
|
||||
#include "profile_vx.h"
|
||||
#endif
|
||||
|
||||
#include "profile_list.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
typedef enum {
|
||||
OUTPUT_TCP = 0,
|
||||
OUTPUT_FILE,
|
||||
OUTPUT_WTX
|
||||
} OutputType;
|
||||
|
||||
typedef struct {
|
||||
FILE* fd;
|
||||
} OutputFile;
|
||||
|
||||
typedef struct {
|
||||
const char * commandName;
|
||||
void (*callbackFunction)(const void*);
|
||||
} CommandIdentifier;
|
||||
|
||||
/* length of longest command (in bytes) we will ever receive */
|
||||
#define MAX_COMMAND_LENGTH (1024)
|
||||
|
||||
typedef struct {
|
||||
char cmdBuff[MAX_COMMAND_LENGTH * 2];
|
||||
void * xmlEngine;
|
||||
RTITcp* tcp;
|
||||
unsigned int cmdStartPosition;
|
||||
RTINtpTime busyConnectionDelay;
|
||||
} TcpLink;
|
||||
|
||||
extern int agentDebuggingOutput;
|
||||
|
||||
#define v0printf printf
|
||||
#define v1printf if (agentDebuggingOutput > 0) v0printf
|
||||
#define v2printf if (agentDebuggingOutput > 1) v0printf
|
||||
#define v3printf if (agentDebuggingOutput > 2) v0printf
|
||||
|
||||
/* default rate of the event loop (in Hz) */
|
||||
#define LOOP_POLL_RATE (100)
|
||||
|
||||
/* maximum recv buff size of target agent */
|
||||
#define RECV_BUFF_SIZE (4096)
|
||||
|
||||
/* default port for tcp link */
|
||||
#define TCPLINK_PORT_DEFAULT (5678)
|
||||
|
||||
/* number of XML commands */
|
||||
#if defined(RTI_LINUX_TGT)
|
||||
# define NUM_LINK_COMMANDS (13)
|
||||
#else
|
||||
# define NUM_LINK_COMMANDS (11)
|
||||
#endif
|
||||
|
||||
/* XML response strings */
|
||||
#define PROFILE_RPCRETURN "RPCReturn"
|
||||
#define PROFILE_CALLSTACK "Callstack"
|
||||
#define PROFILE_CONNECT "Connect"
|
||||
#define PROFILE_THREADLIST "ThreadList"
|
||||
#define PROFILE_NEWTHREAD "NewThread"
|
||||
#define PROFILE_MESSAGE "TargetMessage"
|
||||
|
||||
#if defined(RTI_LINUX_TGT)
|
||||
|
||||
#include <pwd.h>
|
||||
#define OSGetUserId(usrname) getpwnam(usrname)->pw_uid
|
||||
|
||||
#elif defined(RTI_VXWORKS_TGT) || defined(RTI_VXWORKS_HOST)
|
||||
|
||||
#define OSGetUserId(usrname) 0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,290 @@
|
||||
/* tcpOut.c - Send data with Tcp */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003-2009, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
---------------------
|
||||
01b,10oct13,wzc Fix prevent warnings.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
30, 01jun03,pca Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Send data with Tcp.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "targetAgent.h"
|
||||
#include <stdlib.h> /* for strtoul() */
|
||||
#include <rtilib/rti_osapi.h>
|
||||
#include <eventsxml.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
/* how quickly should we retry establishing our connection? (in ms)*/
|
||||
#define CONNECTION_RETRY_DELAY (500)
|
||||
|
||||
/* how quickly should we retry sending data? (in ms)*/
|
||||
#define BUSY_CONNECTION_DELAY (500)
|
||||
|
||||
/* name of default parameter passed to every xml callback */
|
||||
#define DEFAULT_PARAM_NAME "Object"
|
||||
|
||||
|
||||
Package
|
||||
RTIBool TcpConnectionSendData(const TcpLink * const link, const char * data,
|
||||
unsigned int size)
|
||||
{
|
||||
if( size == 0 ) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
if (link->tcp == 0) {
|
||||
v0printf("Sending while unconnected!\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* v3printf("\nSending packet %s", data); */
|
||||
|
||||
while(1) {
|
||||
const int bytesSent =
|
||||
link->tcp->Writen(link->tcp, (char *)data, size);
|
||||
|
||||
if ((unsigned int) bytesSent == size) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
if(bytesSent < 0) {
|
||||
/* write error */
|
||||
const int err = RtiNetioErrnoGet();
|
||||
|
||||
switch (err) {
|
||||
#ifndef RTI_WIN32
|
||||
case ECONNRESET:
|
||||
v0printf("Link ERROR: Host reset connection\n");
|
||||
break;
|
||||
#endif
|
||||
case EWOULDBLOCK:
|
||||
v0printf("Link ERROR: Operation would block\n");
|
||||
break;
|
||||
case EPFNOSUPPORT:
|
||||
v0printf("Link ERROR: protocol not supported\n");
|
||||
break;
|
||||
case ENOTSOCK:
|
||||
v0printf("Link ERROR: operation on non-scocket\n");
|
||||
break;
|
||||
case EADDRINUSE:
|
||||
v0printf("Link ERROR: address already in use\n");
|
||||
break;
|
||||
case EINTR:
|
||||
v0printf("Link ERROR: interrupted system call\n");
|
||||
break;
|
||||
case EISCONN:
|
||||
v0printf("Link ERROR: is already connected\n");
|
||||
break;
|
||||
case EALREADY:
|
||||
v0printf("Link ERROR: operation already in progress\n");
|
||||
break;
|
||||
case EINPROGRESS:
|
||||
v0printf("Link ERROR: operation now in progress\n");
|
||||
break;
|
||||
case ECONNREFUSED:
|
||||
v0printf("Link ERROR: connection refused\n");
|
||||
break;
|
||||
case EMSGSIZE:
|
||||
v0printf("Link ERROR: message size\n");
|
||||
break;
|
||||
case EPIPE:
|
||||
v0printf("Link ERROR: Broken Pipe\n");
|
||||
break;
|
||||
default:
|
||||
v0printf("UNKNOWN LINK ERROR: %d.\n", err);
|
||||
}
|
||||
return RTI_FALSE;
|
||||
|
||||
} else if(bytesSent == 0) {
|
||||
/* RtiMessage("MemScopeDataSend: 0 bytes sent!\n"); */
|
||||
RtiThreadSleep(&link->busyConnectionDelay);
|
||||
} else {
|
||||
/* modify size and pointer for next try */
|
||||
size -= bytesSent;
|
||||
data += bytesSent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
/**
|
||||
*
|
||||
*/
|
||||
RTIBool establishConnection(TcpLink * const link)
|
||||
{
|
||||
RTINtpTime connectionRetryDelay;
|
||||
RTITcpConnectStatus connectionStatus;
|
||||
RtiNtpTimePackFromMillisec(connectionRetryDelay,
|
||||
0, CONNECTION_RETRY_DELAY);
|
||||
|
||||
v2printf("Opening connection\n");
|
||||
|
||||
do {
|
||||
connectionStatus =
|
||||
link->tcp->Connect(link->tcp,0);
|
||||
|
||||
switch(connectionStatus) {
|
||||
case RTI_TCP_CONNECT_OK:
|
||||
v2printf("connected to GUI!\n");
|
||||
return RTI_TRUE;
|
||||
|
||||
case RTI_TCP_CONNECT_INPROGRESS:
|
||||
v2printf(".");
|
||||
break;
|
||||
|
||||
case RTI_TCP_CONNECT_NOTINHOSTTABLE:
|
||||
v0printf("Not in host table\n");
|
||||
return RTI_FALSE;
|
||||
|
||||
case RTI_TCP_CONNECT_REFUSED:
|
||||
v0printf("Connection refused\n");
|
||||
return RTI_FALSE;
|
||||
|
||||
case RTI_TCP_CONNECT_ERROR:
|
||||
v0printf("Problem connecting!\n");
|
||||
return RTI_FALSE;
|
||||
|
||||
default:
|
||||
v0printf("Unknown connection status\n");
|
||||
}
|
||||
RtiThreadSleep(&connectionRetryDelay);
|
||||
} while(1);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/*
|
||||
Initialize the Link structure and initiate a tcp connection.
|
||||
Registers all of the CommandIdentifiers passed as callback functions
|
||||
*/
|
||||
RTIBool TcpConnectionOpen(TcpLink * const link,
|
||||
const unsigned int port,
|
||||
const unsigned long wtxLink,
|
||||
const CommandIdentifier cIDs[],
|
||||
const unsigned int numCommands,
|
||||
void (*callbackfunc)(void))
|
||||
{
|
||||
unsigned int i;
|
||||
char defaultParam[256];
|
||||
|
||||
link->xmlEngine = XMLInit(numCommands);
|
||||
if (link->xmlEngine == 0) {
|
||||
v0printf("Failed to initialize XML engine.\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* Register callbacks for XML commands*/
|
||||
snprintf(defaultParam, sizeof(defaultParam), "<Param " DEFAULT_PARAM_NAME "=%lx></Param>"
|
||||
"<Param profLink=%lu ></Param>", (unsigned long) link, wtxLink);
|
||||
#ifndef RTI_VXWORKS_TGT
|
||||
setDefaultParamValue((unsigned int) wtxLink, link->xmlEngine);
|
||||
#endif
|
||||
for (i = 0; i < numCommands; ++i) {
|
||||
registerFunction(cIDs[i].commandName, cIDs[i].callbackFunction,
|
||||
defaultParam, link->xmlEngine);
|
||||
}
|
||||
|
||||
if (!RtiNetioInit()) {
|
||||
v0printf("Error initializing RTI net libs.\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
link->tcp = RtiTcpNew(RTI_TCP_SERVER, port, RTI_TCP_REUSEPORT);
|
||||
if (link->tcp == 0) {
|
||||
v0printf("ProfileAgent failed to open TCP socket on port %u.\n", port);
|
||||
#if defined (RTI_VXWORKS_TGT)
|
||||
v0printf("Please make this port available and retry the connection.\n");
|
||||
#else
|
||||
v0printf("Please kill any other \"ProfileAgent\" processes running on this"
|
||||
" target and retry the connection.\n");
|
||||
#endif
|
||||
XMLClose(link->xmlEngine);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
link->tcp->ListenBlockingSet(link->tcp, RTI_NETIO_NONBLOCKING);
|
||||
link->tcp->DataBlockingSet(link->tcp, RTI_NETIO_NONBLOCKING);
|
||||
link->tcp->ConnectFailSet(link->tcp, (RTITcpConnectFailFnc) callbackfunc);
|
||||
|
||||
link->cmdStartPosition = 0;
|
||||
RtiNtpTimePackFromMillisec(link->busyConnectionDelay,
|
||||
0, BUSY_CONNECTION_DELAY);
|
||||
|
||||
return establishConnection(link);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
*/
|
||||
void TcpConnectionClose(TcpLink * const link)
|
||||
{
|
||||
RtiTcpDelete(link->tcp);
|
||||
link->tcp = 0;
|
||||
XMLClose(link->xmlEngine);
|
||||
link->xmlEngine = 0;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Check for incoming data on our socket
|
||||
* and attempt to parse it as a command.
|
||||
*/
|
||||
RTIBool TcpConnectionCheckCommand(TcpLink * const link)
|
||||
{
|
||||
char readBuff[MAX_COMMAND_LENGTH];
|
||||
int readLength;
|
||||
|
||||
if (link->tcp == 0) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
readLength = link->tcp->Read(link->tcp,
|
||||
readBuff, MAX_COMMAND_LENGTH);
|
||||
|
||||
if (readLength == RTI_NETIO_ERROR) {
|
||||
v0printf("Error reading commands.\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
if (readLength == 0) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
commandParse(link->cmdBuff, readBuff, readLength,
|
||||
&(link->cmdStartPosition), link->xmlEngine);
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
/**
|
||||
* Parse out a pointer to the TcpLink object which caused this callback
|
||||
*/
|
||||
TcpLink * getLinkFromCallback(const void *xmlEngine)
|
||||
{
|
||||
char *tcpLink = parseParamString(DEFAULT_PARAM_NAME, xmlEngine);
|
||||
if (tcpLink == NULL)
|
||||
return NULL;
|
||||
|
||||
return (TcpLink *)strtoul(tcpLink, (char **) 0, 16);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/* tcpOut.pkg.h - built from: tcpOut.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef tcpOut_pkg_h
|
||||
#define tcpOut_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern RTIBool TcpConnectionSendData(const TcpLink * const link, const char * data,
|
||||
unsigned int size);
|
||||
|
||||
|
||||
/*
|
||||
Initialize the Link structure and initiate a tcp connection.
|
||||
Registers all of the CommandIdentifiers passed as callback functions
|
||||
*/
|
||||
extern RTIBool TcpConnectionOpen(TcpLink * const link,
|
||||
const unsigned int port,
|
||||
const unsigned long wtxLink,
|
||||
const CommandIdentifier cIDs[],
|
||||
const unsigned int numCommands,
|
||||
void (*callbackfunc)(void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
extern void TcpConnectionClose(TcpLink * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Check for incoming data on our socket
|
||||
* and attempt to parse it as a command.
|
||||
*/
|
||||
extern RTIBool TcpConnectionCheckCommand(TcpLink * const link);
|
||||
|
||||
|
||||
/**
|
||||
* Parse out a pointer to the TcpLink object which caused this callback
|
||||
*/
|
||||
extern TcpLink * getLinkFromCallback(const void *xmlEngine);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* tcpOut_pkg_h */
|
||||
@@ -0,0 +1,31 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
# 01a,10apr08,pca created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../../..
|
||||
|
||||
LIB_BASE_NAME = profile
|
||||
|
||||
EXTRA_DEFINE = -DSCOPEPROFILEVERSION=\"4.11a\" -DRTI_VXWORKS_TGT
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include/vx \
|
||||
-I$(COMP_STACKTRACE_PATH)/include \
|
||||
-I$(TOOLS_SRC_ROOT)/scopeutils/include \
|
||||
-I.. -I../../include
|
||||
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= main.o wtxcalls.o
|
||||
|
||||
PKG_H =
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
@@ -0,0 +1,634 @@
|
||||
/*mangen ProfileScopeInterface - A dynamic system profiler for RTOSs. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005-2009, 2011, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01c,10oct13,wzc Fix prevent warnings.
|
||||
01b,30jun11,wzc Porting stacktrace-1.0 into analysis.(RQ:WIND00061556)
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
6.7.2a,18dec08,mas fixed memory leak (WIND00147287)
|
||||
6.7c,17nov08,flu add interface to get version number (WIND00134834)
|
||||
6.7b,02oct08,mas Added Context Cache Support and _WRS_CONFIG_SMP + vsbConfig.h
|
||||
6.7a,16may08,tpw copied to CC from CVS repository label clearcase_drop_24apr08
|
||||
4.11,24Aug06,mas Fixed Def56923: added textStartAdrs unconditionally to
|
||||
ProfileScopeInit, added conditionally: call to
|
||||
stContextUnint, and VxWorks support files
|
||||
rtilib/vxVersions.h, rtitools/rtitools_context.h
|
||||
4.8a,27oct05,mas Added file header w/history; fixed bug 10739: appended
|
||||
textEndAdrs to ProfileScopeInit
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
ProfileScope is the dynamic system-analysis tool for real-time operating
|
||||
systems. ProfileScope analyzes tasks and subroutine usage in a running
|
||||
real-time system. It provides a live summary of each task in the
|
||||
system. ProfileScope helps you understand your task loading and finds
|
||||
overloaded, slow tasks quickly - before they compromise your system.
|
||||
|
||||
SEE ALSO:
|
||||
ProfileScopeInit(3)
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <st_stacktrace.h>
|
||||
#include "stddef.h"
|
||||
#include "targetAgent.h"
|
||||
|
||||
#include <rtilib/rti_osapi.h>
|
||||
#if defined(RTI_VXWORKS_TGT)
|
||||
# include <rtilib/vxVersions.h>
|
||||
#endif
|
||||
#include <rtitools/rtitools_hash.h>
|
||||
|
||||
#include "communications.pkg.h"
|
||||
#include "tcpOut.pkg.h"
|
||||
#include "fileOut.pkg.h"
|
||||
|
||||
#if defined(RTI_VXWORKS_TGT)
|
||||
# include "wtxcalls.pkg.h"
|
||||
# undef SMP_CONFIG
|
||||
# if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# include <vxCpuLib.h>
|
||||
# endif
|
||||
# else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# include <vxCpuLib.h>
|
||||
# endif
|
||||
# endif
|
||||
#elif defined(RTI_VXWORKS_HOST)
|
||||
# include "proflink.pkg.h"
|
||||
#else
|
||||
# error "RTI_VXWORKS_TGT or RTI_VXWORKS_HOST needs to be defined"
|
||||
#endif
|
||||
|
||||
/* defines */
|
||||
|
||||
#if defined(RTI_WIN32)
|
||||
/* visual studio doesn't provide snprintf() */
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
Public unsigned int PROFILESCOPE_LIB_VERSION = 0x00040b00;
|
||||
|
||||
/* until rti_osapi.h declares this function */
|
||||
void RtiThreadDelete (RTIThreadId tid);
|
||||
|
||||
typedef struct {
|
||||
struct RTI_list_head node;
|
||||
unsigned int tid;
|
||||
} tidListNode;
|
||||
|
||||
typedef struct {
|
||||
struct RTI_list_head tidList;
|
||||
int existsCheck;
|
||||
char* name; /* TD: use name to keep track of existance of RTP */
|
||||
} ProcessStruct;
|
||||
|
||||
typedef struct {
|
||||
unsigned int pollrate;
|
||||
unsigned int port;
|
||||
char* file;
|
||||
unsigned long wtxLink;
|
||||
} ThreadParamStruct;
|
||||
|
||||
struct {
|
||||
RTIBool shouldStop;
|
||||
ProfileInfo pi;
|
||||
RtiTools_HashTable pidhash;
|
||||
OutputType oType;
|
||||
void* link;
|
||||
RTIThreadId tid;
|
||||
char recvBuff[RECV_BUFF_SIZE];
|
||||
} TargetAgent;
|
||||
|
||||
int agentDebuggingOutput = 0;
|
||||
ThreadParamStruct threadParams;
|
||||
|
||||
#define PROFILE_LINK_NAME "ProfileAgent"
|
||||
#define DEFAULT_LINK_PRIORITY 156
|
||||
#define PROFILE_EXISTS_CHECK_Nth 100
|
||||
|
||||
|
||||
void ProfileScopeShutdown(void);
|
||||
void ProfileScopeShutdownInternal(void);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OSGetNumCPUs - get number of CPUs in system
|
||||
*
|
||||
* This routine returns the configured number of CPUs in the system.
|
||||
* NOTE: this number may not reflect the actual number of CPUs enabled!
|
||||
*
|
||||
* RETURNS: number of CPUs configured
|
||||
*/
|
||||
|
||||
static inline int OSGetNumCPUs (void)
|
||||
{
|
||||
#ifdef SMP_CONFIG
|
||||
return (vxCpuConfiguredGet());
|
||||
#else
|
||||
return (1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
RTIBool SendData(void* link, char* buffer, int size)
|
||||
{
|
||||
/* send data over the socket or file */
|
||||
if (TargetAgent.oType == OUTPUT_TCP) {
|
||||
return TcpConnectionSendData((TcpLink*) link, buffer, size);
|
||||
} else {
|
||||
return OutputFileSendData((OutputFile*) link, buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
Private
|
||||
RTIBool SendNewThreadMsg(void* link, unsigned long wtxLink,
|
||||
ProfileMsg msg, ProcessStruct* ps)
|
||||
{
|
||||
char *threadname, *msgstr;
|
||||
unsigned int tid = msg->tid;
|
||||
tidListNode* tidNode = NULL;
|
||||
|
||||
/* for idle kernel condition, create a fake threadname */
|
||||
if (msg->pentity == IDLE_THREAD) {
|
||||
threadname = "Idle Task";
|
||||
goto send_newthreadmsg;
|
||||
} else if (msg->pentity == KERNEL_STATE) {
|
||||
threadname = "Kernel State";
|
||||
goto send_newthreadmsg;
|
||||
} else if (msg->pentity == KERNEL_INTERRUPT) {
|
||||
threadname = "Interrupt";
|
||||
goto send_newthreadmsg;
|
||||
} else if (msg->pentity == KERNEL_EXCEPTION) {
|
||||
threadname = "Exception";
|
||||
goto send_newthreadmsg;
|
||||
}
|
||||
|
||||
if (TgtTaskIdVerify(msg->tid, wtxLink) == RTI_FALSE) {
|
||||
v1printf("task (tid: 0x%x) is invalid!\n", msg->tid);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
TgtTaskName(msg->tid, &threadname, wtxLink);
|
||||
if (threadname == NULL) {
|
||||
v1printf("task (tid: 0x%x) is invalid!\n", msg->tid);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* make the new thread message string */
|
||||
/* 123456789012345678901234567890123456789012345678901234567890 */
|
||||
send_newthreadmsg:
|
||||
msgstr = (char*) malloc(200+strlen(threadname));
|
||||
if (msgstr == NULL) {
|
||||
v0printf("Couldn't allocate msgstr!\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
snprintf(msgstr, 200+strlen(threadname),
|
||||
"<" PROFILE_NEWTHREAD " tid=\"%x\" pid=\"%x\" pentity=\"%d\" "
|
||||
"name=\"%s\"></" PROFILE_NEWTHREAD ">", tid, msg->pid,
|
||||
msg->pentity, threadname);
|
||||
v2printf("\nnew thread=> name: %s, tid: 0x%x", threadname, tid);
|
||||
v2printf(", pid: 0x%x, type: %d\n", msg->pid, msg->pentity);
|
||||
|
||||
/* send data over the socket or file */
|
||||
if (SendData(link, msgstr, strlen(msgstr)) == RTI_FALSE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
free(msgstr);
|
||||
|
||||
/* add the new thread to the list of threads in a process node */
|
||||
tidNode = (tidListNode*) malloc(sizeof(tidListNode));
|
||||
if (tidNode == NULL) {
|
||||
v0printf("Couldn't allocate tidNode!\n");
|
||||
return RTI_FALSE;
|
||||
}
|
||||
tidNode->tid = tid;
|
||||
RTI_list_add_tail(&tidNode->node, &ps->tidList);
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
RTIBool CheckForNewThread(void* link, unsigned long wtxLink, ProfileMsg msg)
|
||||
{
|
||||
ProcessStruct* ps = NULL;
|
||||
unsigned int tid = msg->tid;
|
||||
struct RTI_list_head *trav, *temp;
|
||||
|
||||
/* check if the current thread has any */
|
||||
if (RtiTools_HashTableGet(&TargetAgent.pidhash, (void*) msg->pid,
|
||||
(void*) &ps) == RTI_FALSE) {
|
||||
ps = (ProcessStruct *) malloc(sizeof(ProcessStruct));
|
||||
if (ps == NULL) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
RTI_INIT_LIST_HEAD(&ps->tidList);
|
||||
ps->existsCheck = 0;
|
||||
(void)RtiTools_HashTableInsert(&TargetAgent.pidhash, (void*) ps,
|
||||
(void*) msg->pid);
|
||||
}
|
||||
|
||||
/* check whether current thread is listed in the process group */
|
||||
RTI_list_for_each_safe(trav, temp, &ps->tidList) {
|
||||
tidListNode* tidNode = RTI_list_entry(trav, tidListNode, node);
|
||||
|
||||
if (tidNode->tid == tid)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this thread is new in the corresponding process, send NEWTHREAD
|
||||
message to the GUI */
|
||||
if (trav == &ps->tidList) {
|
||||
ps->existsCheck = 0;
|
||||
|
||||
if (SendNewThreadMsg(link, wtxLink, msg, ps) == RTI_FALSE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->pentity == IDLE_THREAD || msg->pentity == KERNEL_STATE ||
|
||||
msg->pentity == KERNEL_INTERRUPT || msg->pentity == KERNEL_EXCEPTION) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
if (ps->existsCheck) {
|
||||
ps->existsCheck--;
|
||||
return RTI_TRUE;
|
||||
}
|
||||
ps->existsCheck = PROFILE_EXISTS_CHECK_Nth;
|
||||
|
||||
/* drop this sample if the thread doesn't exist */
|
||||
if (TgtTaskIdVerify(tid, wtxLink) == RTI_FALSE) {
|
||||
v1printf("Task (tid: 0x%x) doesn't exist!\n", tid);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
RTIBool TargetAgentMsgsSend(char* buffer, int size, void* link,
|
||||
unsigned long wtxLink)
|
||||
{
|
||||
/* size of buffer used to send a single sample */
|
||||
#define PROFILE_MSG_LEN (250+PROFILE_MAX_STACK_DEPTH*10)
|
||||
|
||||
ProfileMsg msg = NULL;
|
||||
char msgstr[PROFILE_MSG_LEN];
|
||||
unsigned int ptr, j;
|
||||
int msg_len;
|
||||
#if defined(DUMP_ALL_STACKS)
|
||||
static unsigned int numCallstacks = 0;
|
||||
#endif
|
||||
|
||||
if (size < 0) {
|
||||
v0printf("Error sending data to host, error=%d.\n", size);
|
||||
return RTI_FALSE;
|
||||
} else if (size == 0) {
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
ptr = (unsigned int) buffer;
|
||||
while (ptr < ((unsigned int) buffer+size))
|
||||
{
|
||||
msg = (ProfileMsg) ptr;
|
||||
if (CheckForNewThread(link, wtxLink, msg) == RTI_FALSE) {
|
||||
goto next_packet;
|
||||
}
|
||||
|
||||
/* send sample data */
|
||||
msg_len = snprintf(msgstr, PROFILE_MSG_LEN,
|
||||
"<" PROFILE_CALLSTACK " cpuid=\"%d\" tid=\"%x\" pid=\"%x\" "
|
||||
"stack=\"",
|
||||
msg->cpuid, msg->tid, msg->pid);
|
||||
|
||||
for (j = 0; j < (unsigned int) msg->numSamples; ++j) {
|
||||
msg_len += snprintf(msgstr + msg_len, PROFILE_MSG_LEN - msg_len,
|
||||
"%lx ", (unsigned long) msg->stack[j]);
|
||||
}
|
||||
|
||||
msg_len += snprintf(msgstr + msg_len, PROFILE_MSG_LEN - msg_len,
|
||||
"\"></" PROFILE_CALLSTACK ">");
|
||||
|
||||
#if defined(DUMP_ALL_STACKS)
|
||||
++numCallstacks;
|
||||
/* print each sample, exclude idle task */
|
||||
if (msg->tid) {
|
||||
v3printf("Message(%u): %s\n", numCallstacks, msgstr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* send data over the socket or file */
|
||||
if (SendData(link, msgstr, strlen(msgstr)) == RTI_FALSE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
next_packet:
|
||||
/* point to next element */
|
||||
ptr += offsetof(ProfileMsgStorage, stack) +
|
||||
(sizeof(void*) * msg->numSamples);
|
||||
}
|
||||
|
||||
#if defined(DUMP_ALL_STACKS)
|
||||
if ((msg != NULL) && (msg->tid)) {
|
||||
v3printf("Sent %d stacks\n", numCallstacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
return RTI_TRUE;
|
||||
|
||||
#undef PROFILE_MSG_LEN
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
RTIBool SendConnectMsg(void* link, unsigned long wtxLink)
|
||||
{
|
||||
char msgstr[150];
|
||||
int len;
|
||||
|
||||
snprintf(msgstr, sizeof(msgstr), "<" PROFILE_CONNECT " cpus=\"%d\"", OSGetNumCPUs());
|
||||
len = strlen(msgstr);
|
||||
|
||||
/* get target archicture type and clocks available */
|
||||
TgtGetClkTypeArch(&msgstr[len], wtxLink, sizeof(msgstr) - len);
|
||||
len = strlen(msgstr);
|
||||
|
||||
snprintf(&msgstr[len], sizeof(msgstr) - len, "></" PROFILE_CONNECT ">");
|
||||
v1printf("sending init mesg: %s\n", msgstr);
|
||||
|
||||
/* send data over the socket or file */
|
||||
if (SendData(link, msgstr, strlen(msgstr)) == RTI_FALSE) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void runTcpMode(ThreadParamStruct* params)
|
||||
{
|
||||
TcpLink* tcpLink;
|
||||
int size, msec = 1000/params->pollrate;
|
||||
RTINtpTime sleepTime;
|
||||
unsigned long wtxLink;
|
||||
|
||||
if (msec == 0) {
|
||||
msec = 1;
|
||||
}
|
||||
|
||||
TargetAgent.link = (void *) malloc(sizeof(TcpLink));
|
||||
if (TargetAgent.link == 0) {
|
||||
v0printf("failed to spawn TcpLink!\n");
|
||||
return;
|
||||
}
|
||||
tcpLink = (TcpLink*) TargetAgent.link;
|
||||
wtxLink = params->wtxLink;
|
||||
|
||||
if (TcpConnectionOpen(tcpLink, params->port, wtxLink, Commands,
|
||||
NUM_LINK_COMMANDS, ProfileScopeShutdown)
|
||||
!= RTI_TRUE) {
|
||||
v0printf("failed to establish tcp connection\n");
|
||||
|
||||
/* cleanup */
|
||||
ProfileScopeShutdownInternal();
|
||||
return;
|
||||
}
|
||||
|
||||
/* send init message to host */
|
||||
SendConnectMsg((void*) tcpLink, wtxLink);
|
||||
RtiNtpTimePackFromMillisec(sleepTime, 0, msec);
|
||||
|
||||
while( TargetAgent.shouldStop == RTI_FALSE ) {
|
||||
/* get as much context data as possible */
|
||||
do {
|
||||
if (TcpConnectionCheckCommand(tcpLink) != RTI_TRUE) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
size = TgtProfileMsgsReceive(&TargetAgent.recvBuff,
|
||||
RECV_BUFF_SIZE, wtxLink);
|
||||
|
||||
/* send the data to host */
|
||||
if (TargetAgentMsgsSend(TargetAgent.recvBuff, size,
|
||||
(void*) tcpLink, wtxLink)
|
||||
== RTI_FALSE) {
|
||||
goto cleanup;
|
||||
}
|
||||
} while ((size > 0) &&
|
||||
((size+offsetof(ProfileMsgStorage, stack)) >= RECV_BUFF_SIZE));
|
||||
|
||||
/* sleep */
|
||||
RtiThreadSleep(&sleepTime);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* cleanup */
|
||||
ProfileScopeShutdownInternal();
|
||||
}
|
||||
|
||||
|
||||
Private
|
||||
void runFileMode(int pollrate, char* file)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Package functions
|
||||
*/
|
||||
|
||||
Package
|
||||
void GetProfileStatus(void* link, ProfileInfo pi)
|
||||
{
|
||||
#define BUF_LEN 256
|
||||
|
||||
char buffer[BUF_LEN];
|
||||
int size;
|
||||
|
||||
size = ProfileGetStatus(buffer, BUF_LEN, TargetAgent.pi,
|
||||
((TcpLink*) link)->xmlEngine);
|
||||
|
||||
/* send data over the socket or file */
|
||||
(void)SendData(link, buffer, size);
|
||||
|
||||
#undef BUF_LEN
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
ProfileInfo GetProfileInfo(void)
|
||||
{
|
||||
return TargetAgent.pi;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void SetProfileInfo(ProfileInfo pi)
|
||||
{
|
||||
TargetAgent.pi = pi;
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void ProfileScopeShutdown(void) {
|
||||
TargetAgent.shouldStop = RTI_TRUE;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
void ProfileScopeShutdownInternal(void)
|
||||
{
|
||||
RtiTools_HashIterator iter =
|
||||
RtiTools_HashIteratorGet(&TargetAgent.pidhash);
|
||||
|
||||
/* cleanup the sampler side */
|
||||
ProfileCleanup(((TcpLink*) TargetAgent.link)->xmlEngine);
|
||||
|
||||
/* close the TCP connection */
|
||||
if (TargetAgent.link != 0) {
|
||||
if (TargetAgent.oType == OUTPUT_TCP) {
|
||||
TcpConnectionClose((TcpLink*) TargetAgent.link);
|
||||
} else {
|
||||
OutputFileClose((OutputFile*) TargetAgent.link);
|
||||
}
|
||||
free(TargetAgent.link);
|
||||
TargetAgent.link = 0;
|
||||
}
|
||||
|
||||
/* delete pidhash */
|
||||
for (; (iter != 0);) {
|
||||
ProcessStruct* ps =
|
||||
(ProcessStruct*) RtiTools_HashIteratorGetData(iter);
|
||||
if (ps) {
|
||||
struct RTI_list_head *trav, *temp;
|
||||
RTI_list_for_each_safe(trav, temp, &ps->tidList) {
|
||||
RTI_list_del(trav);
|
||||
free(RTI_list_entry(trav, tidListNode, node));
|
||||
}
|
||||
free(ps);
|
||||
}
|
||||
iter = RtiTools_HashIteratorNext(&TargetAgent.pidhash, iter);
|
||||
}
|
||||
RtiTools_HashTableDestroy(&TargetAgent.pidhash);
|
||||
|
||||
/* delete rtilib thread structures */
|
||||
if (TargetAgent.tid != 0) {
|
||||
#if defined(RTI_UNIX)
|
||||
RtiThreadTerminate(TargetAgent.tid);
|
||||
#else
|
||||
RtiThreadDelete(TargetAgent.tid);
|
||||
#endif
|
||||
TargetAgent.tid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
int ProfileScopeAgentVersionGet(void)
|
||||
{
|
||||
return PROFILESCOPE_LIB_VERSION;
|
||||
}
|
||||
|
||||
|
||||
Public
|
||||
int ProfileScopeInit (int verbosity,
|
||||
int pollrate,
|
||||
int linkPriority,
|
||||
int port,
|
||||
RTIBool wtxMode,
|
||||
char * file,
|
||||
void * textStartAdrs,
|
||||
void * textEndAdrs,
|
||||
unsigned long wtxLink)
|
||||
{
|
||||
RTIThreadOptions options = RTI_THREAD_STDIO | RTI_THREAD_FLOATING_POINT |
|
||||
RTI_THREAD_PRIORITY_ENFORCE;
|
||||
|
||||
/* verify parameters */
|
||||
if (pollrate <= 1) {
|
||||
pollrate = LOOP_POLL_RATE;
|
||||
}
|
||||
|
||||
/* switch to default native priority level if linkPriority is invalid */
|
||||
if (RtiThreadPriorityOK(linkPriority, options) == RTI_FALSE) {
|
||||
linkPriority = RtiThreadNativePriorityGet(options,
|
||||
DEFAULT_LINK_PRIORITY);
|
||||
}
|
||||
|
||||
/* zero out TargetAgent structure */
|
||||
memset ((char*) &TargetAgent, 0, sizeof(TargetAgent));
|
||||
|
||||
if (file != NULL) {
|
||||
TargetAgent.oType = OUTPUT_FILE;
|
||||
} else if (wtxMode == RTI_FALSE) {
|
||||
TargetAgent.oType = OUTPUT_TCP;
|
||||
} else {
|
||||
TargetAgent.oType = OUTPUT_WTX;
|
||||
}
|
||||
|
||||
/* following code is executed on target only */
|
||||
#if defined(RTI_VXWORKS_TGT)
|
||||
/* initialize context library */
|
||||
if (ST_context_init (textStartAdrs, textEndAdrs) == RTI_FALSE) {
|
||||
v0printf("Initialization of context library failed\n");
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
TgtProfileScopeInit(wtxMode, verbosity);
|
||||
#endif
|
||||
|
||||
/* set a global verbosity level */
|
||||
agentDebuggingOutput = verbosity;
|
||||
|
||||
/* initialize the pidhash */
|
||||
if (RtiTools_HashTableInit(&TargetAgent.pidhash, 8, 0) == RTI_FALSE) {
|
||||
ProfileScopeShutdownInternal();
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* start the agent thread */
|
||||
threadParams.pollrate = pollrate;
|
||||
threadParams.file = file;
|
||||
threadParams.port = port;
|
||||
threadParams.wtxLink = wtxLink;
|
||||
|
||||
switch (TargetAgent.oType) {
|
||||
case OUTPUT_TCP:
|
||||
TargetAgent.tid =
|
||||
RtiThreadCreate(PROFILE_LINK_NAME, linkPriority, options,
|
||||
16*1024, (RTIThreadStartRtn) runTcpMode,
|
||||
(void*) &threadParams);
|
||||
break;
|
||||
|
||||
case OUTPUT_FILE:
|
||||
TargetAgent.tid =
|
||||
RtiThreadCreate(PROFILE_LINK_NAME, linkPriority, options,
|
||||
16*1024, (RTIThreadStartRtn) runFileMode,
|
||||
(void*) &threadParams);
|
||||
break;
|
||||
case OUTPUT_WTX:
|
||||
break;
|
||||
}
|
||||
|
||||
return RTI_TRUE;
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/* wtxcalls.c - WTX interface code. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004-2009, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01c,10oct13,wzc Fix prevent warnings.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
33a,01jul09,wzc Fix Coverity Prevent error NO EFFECT in line 61
|
||||
33a,30jan07,mas made SMP-compliant
|
||||
20a,23nov04,avd Written
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
WTX interface code.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#include <usrConfig.h>
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
|
||||
#include <rtitools/target_license.h>
|
||||
#include <rtitools/rtitools_clock.h>
|
||||
#include <rtitools/rtitools_msgq.h>
|
||||
|
||||
#include "targetAgent.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
struct {
|
||||
RTIBool wtxMode;
|
||||
char wtxRecvBuff[RECV_BUFF_SIZE];
|
||||
} WTXLink;
|
||||
|
||||
#define KERNEL_ID kernelIdGet()
|
||||
|
||||
|
||||
Package
|
||||
RTIBool TgtTaskIdVerify (int tid, unsigned long wtxLink)
|
||||
{
|
||||
if (taskIdVerify (tid) == OK) {
|
||||
return (RTI_TRUE);
|
||||
}
|
||||
return (RTI_FALSE);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
int TgtTaskName (int tid, char** name, unsigned long wtxLink)
|
||||
{
|
||||
char* str = taskName (tid);
|
||||
if (str == NULL) {
|
||||
if (name != NULL) {
|
||||
*name = str;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (WTXLink.wtxMode == RTI_TRUE) {
|
||||
int len = strlen (str) + 1;
|
||||
|
||||
bcopy (str, WTXLink.wtxRecvBuff, len);
|
||||
return (len);
|
||||
}
|
||||
*name = str;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
int TgtProfileMsgsReceive (void *buffer, unsigned int bufsize,
|
||||
unsigned long wtxLink)
|
||||
{
|
||||
if (WTXLink.wtxMode == RTI_TRUE) {
|
||||
buffer = (void*) WTXLink.wtxRecvBuff;
|
||||
bufsize = RECV_BUFF_SIZE;
|
||||
}
|
||||
return (ProfileMsgsReceive (buffer, bufsize));
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
int TgtGetClkTypeArch (char* buffer, unsigned long wtxLink, size_t len)
|
||||
{
|
||||
if (WTXLink.wtxMode == RTI_TRUE) {
|
||||
buffer = (void*) WTXLink.wtxRecvBuff;
|
||||
snprintf(buffer, RECV_BUFF_SIZE, " clocks=\"%s\" kernelId=\"%p\"",
|
||||
RTIClkTypeGet(), KERNEL_ID);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, len, " clocks=\"%s\" kernelId=\"%p\"",
|
||||
RTIClkTypeGet(), KERNEL_ID);
|
||||
}
|
||||
return (strlen (buffer) + 1);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
unsigned int TgtWTXBuffAddrGet (void)
|
||||
{
|
||||
if (WTXLink.wtxMode == RTI_TRUE) {
|
||||
return ((unsigned int)WTXLink.wtxRecvBuff);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
unsigned int TgtProfileGetStatus (ProfileInfo pi, void* xmlEngine)
|
||||
{
|
||||
return (ProfileGetStatus (WTXLink.wtxRecvBuff, RECV_BUFF_SIZE, pi,
|
||||
xmlEngine));
|
||||
}
|
||||
|
||||
|
||||
Package
|
||||
void TgtProfileScopeInit (const RTIBool wtxMode, const int verbosity)
|
||||
{
|
||||
ProfileDebuggingOutput = ClockDebuggingOutput =
|
||||
MsgQDebuggingOutput = verbosity;
|
||||
|
||||
if (wtxMode == RTI_TRUE) {
|
||||
WTXLink.wtxMode = RTI_TRUE;
|
||||
} else {
|
||||
WTXLink.wtxMode = RTI_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* wtxcalls.pkg.h - built from: /view/ot.40_RCPL8.2024030303/vobs/rtca/component_roots/comp_rtca/target/src/profile/targetAgent/vx/wtxcalls.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef wtxcalls_pkg_h
|
||||
#define wtxcalls_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern RTIBool TgtTaskIdVerify (int tid, unsigned long wtxLink);
|
||||
|
||||
|
||||
extern int TgtTaskName (int tid, char** name, unsigned long wtxLink);
|
||||
|
||||
|
||||
extern int TgtProfileMsgsReceive (void *buffer, unsigned int bufsize,
|
||||
unsigned long wtxLink);
|
||||
|
||||
|
||||
extern int TgtGetClkTypeArch (char* buffer, unsigned long wtxLink, size_t len);
|
||||
|
||||
|
||||
extern unsigned int TgtWTXBuffAddrGet (void);
|
||||
|
||||
|
||||
extern unsigned int TgtProfileGetStatus (ProfileInfo pi, void* xmlEngine);
|
||||
|
||||
|
||||
extern void TgtProfileScopeInit (const RTIBool wtxMode, const int verbosity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* wtxcalls_pkg_h */
|
||||
@@ -0,0 +1,17 @@
|
||||
# Makefile - makefile for building scopetools rti library
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,26mar08,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the rti library
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ..
|
||||
|
||||
SUBDIRS = utils vxlibs/float
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
@@ -0,0 +1,49 @@
|
||||
/* fastBuffer.h - built from: fastBuffer.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef fastBuffer_h
|
||||
#define fastBuffer_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
# include <rtilib/rti_types.h>
|
||||
|
||||
typedef struct FastBufferTag *FastBufferID;
|
||||
|
||||
extern DllExport
|
||||
void *FastBufferAddPool( FastBufferID poolID );
|
||||
|
||||
extern DllExport
|
||||
void FastBufferClearPool( FastBufferID poolID );
|
||||
|
||||
extern DllExport
|
||||
FastBufferID FastBufferCreatePool ( int nBuffers, int bufSize );
|
||||
|
||||
extern DllExport
|
||||
void FastBufferDestroyPool ( FastBufferID poolID );
|
||||
|
||||
extern DllExport
|
||||
void *FastBufferGet ( FastBufferID poolID );
|
||||
|
||||
extern DllExport
|
||||
void *FastBufferGetAutoAddPool ( FastBufferID poolID );
|
||||
|
||||
extern DllExport
|
||||
void FastBufferReturn ( void *buffer );
|
||||
|
||||
extern DllExport
|
||||
void FastBufferDisplay( FastBufferID poolID );
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* fastBuffer_h */
|
||||
@@ -0,0 +1,48 @@
|
||||
/* makeheader.h - generated by: makeheader */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
generated by: makeheader Wed Oct 7 15:27:08 1998
|
||||
built from: src/makeheader.c
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
/* defines */
|
||||
|
||||
|
||||
#ifndef makeheader_h
|
||||
#define makeheader_h
|
||||
|
||||
|
||||
#if defined(RTI_WIN32) || defined(_WIN32)
|
||||
#pragma warning(disable:4068)
|
||||
#endif
|
||||
|
||||
#define Public
|
||||
#define Package
|
||||
#define Peer
|
||||
#define Private static
|
||||
#ifndef __cplusplus
|
||||
#define public
|
||||
#define package
|
||||
#define peer
|
||||
#define private static
|
||||
#endif /* !__cplusplus */
|
||||
|
||||
#endif /* makeheader_h */
|
||||
@@ -0,0 +1,260 @@
|
||||
/* rti_endian.h - built from: endian.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_endian_h
|
||||
#define rti_endian_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(__VXWORKS__)
|
||||
# include <vxWorks.h> /* for _BYTE_ORDER */
|
||||
#endif
|
||||
|
||||
#include "rtilib/rti_types.h" /* for DllExport */
|
||||
|
||||
/* defines */
|
||||
|
||||
/*
|
||||
* ALPHA's long is 64 bits
|
||||
*/
|
||||
#if defined(RTI_UNIX) || defined(RTI_VXWORKS) || defined(RTI_OPENVMS)
|
||||
/**
|
||||
Atomic type that is 32 bits.
|
||||
*/
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
/**
|
||||
Atomic type that is 16 bit integer.
|
||||
*/
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
/**
|
||||
Atomic type that is 8 bit integer.
|
||||
*/
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
/**
|
||||
Atomic type that is 32 bit float.
|
||||
*/
|
||||
typedef float RTI_FLOAT32;
|
||||
/**
|
||||
Atomic type that is 64 bit float.
|
||||
*/
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
#if defined(RTI_PSOS)
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
#if defined(RTI_NETOS)
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
#if defined(RTI_LYNX)
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
#if defined(RTI_QNX)
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
#if defined(RTI_INTY)
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
#ifdef RTI_WIN32
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef char RTI_INT8;
|
||||
typedef unsigned char RTI_UINT8;
|
||||
typedef short RTI_INT16;
|
||||
typedef unsigned short RTI_UINT16;
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif /* RTI_WIN32 */
|
||||
|
||||
/* On Windows CE, some of these are defined in the system header file
|
||||
* types.h!
|
||||
*/
|
||||
#if defined(RTI_WINCE) || defined(RTI_WINCE30)
|
||||
typedef float RTI_FLOAT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(RTI_WISP)
|
||||
typedef int RTI_INT32;
|
||||
typedef unsigned int RTI_UINT32;
|
||||
typedef double RTI_DOUBLE64;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Indicates whether this type is unsigned or signed. 5th bit = 0
|
||||
* means signed, 5th bit = 1 means unsigned.
|
||||
*/
|
||||
#define RTIAtomicTypeUnsignBit (0x10)
|
||||
|
||||
/*
|
||||
* To extract the type information.
|
||||
*/
|
||||
#define RTIAtomicTypeMask (0x0f)
|
||||
|
||||
typedef enum {
|
||||
RTI_ENDIAN_ENUM_UNKNOWN = -1,
|
||||
RTI_ENDIAN_ENUM_LITTLE = 0,
|
||||
RTI_ENDIAN_ENUM_BIG = 1
|
||||
} RTIEndian;
|
||||
|
||||
typedef enum {
|
||||
RTI_NOTYPE = 0,
|
||||
RTI_INT8ID = 0x01,
|
||||
RTI_INT16ID = 0x02,
|
||||
RTI_INT32ID = 0x04,
|
||||
RTI_UINT8ID = RTIAtomicTypeUnsignBit | RTI_INT8ID,
|
||||
RTI_UINT16ID = RTIAtomicTypeUnsignBit | RTI_INT16ID,
|
||||
RTI_UINT32ID = RTIAtomicTypeUnsignBit | RTI_INT32ID,
|
||||
RTI_FLOAT32ID = 0x05,
|
||||
RTI_DOUBLE64ID = 0x08
|
||||
} RTIAtomicTypeId;
|
||||
|
||||
#if !defined(RTI_WISP)
|
||||
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeCharGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeUCharGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeShortGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeUShortGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeIntGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeUIntGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeLongGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeULongGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeFloatGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIAtomicTypeId RtiAtomicTypeDoubleGet(void);
|
||||
|
||||
extern DllExport
|
||||
int RtiAtomicTypeBytesGet(RTIAtomicTypeId type);
|
||||
|
||||
extern DllExport
|
||||
void RtiEndianSwapInt32(RTI_INT32 *Num);
|
||||
|
||||
extern DllExport
|
||||
void RtiEndianSwapDouble64(RTI_DOUBLE64 *Num);
|
||||
|
||||
extern DllExport
|
||||
void RtiEndianSwapFloat32(RTI_FLOAT32 *Num);
|
||||
|
||||
extern DllExport
|
||||
void RtiEndianSwapInt16(RTI_INT16 *Num);
|
||||
|
||||
extern DllExport
|
||||
void RtiEndianSwapInt8(RTI_INT8 *Num);
|
||||
|
||||
|
||||
/*e \ingroup rtiEnd
|
||||
|
||||
@brief Returns the local machine endian.
|
||||
|
||||
This is supported through the compile flag RTI_ENDIAN_BIG, so you must
|
||||
make sure that this is correct.
|
||||
|
||||
@retval RTI_ENDIAN_ENUM_LITTLE on a little endian machine.
|
||||
@retval RTI_ENDIAN_ENUM_BIG on a big endian machine.
|
||||
*/
|
||||
|
||||
#if defined(RTI_ENDIAN_BIG)
|
||||
#define RtiEndianGet() (RTI_ENDIAN_ENUM_BIG)
|
||||
#endif
|
||||
|
||||
/* gcc 2.95 on solaris 8 complained about having this construct:
|
||||
if defined(RTI_ENDIAN_BIG) \
|
||||
|| ( defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN) )
|
||||
|
||||
so we split out the conditional into separate statements.
|
||||
*/
|
||||
#if defined(_BYTE_ORDER)
|
||||
# if (_BYTE_ORDER == _BIG_ENDIAN)
|
||||
# define RtiEndianGet() (RTI_ENDIAN_ENUM_BIG)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(RtiEndianGet)
|
||||
#define RtiEndianGet() (RTI_ENDIAN_ENUM_LITTLE)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* RTI_WISP */
|
||||
|
||||
|
||||
extern RTI_UINT32 *RTICrossEtoLittleE(RTI_UINT32* crossEndian);
|
||||
|
||||
extern RTI_UINT32 *RTICrossEtoBigE(RTI_UINT32* crossEndian);
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_endian_h */
|
||||
@@ -0,0 +1,607 @@
|
||||
/* rti_ip.h - built from: netio_common.c, netioGlobals.c
|
||||
, netio_new.c
|
||||
, netioUtils.c
|
||||
, connect.c
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_ip_h
|
||||
#define rti_ip_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(RTI_PSOS)
|
||||
#define SOCKADDRIN2OS(x) (x)
|
||||
#else
|
||||
#define SOCKADDRIN2OS(x) (struct sockaddr *)(x)
|
||||
#endif
|
||||
|
||||
/* NetIO Error API
|
||||
|
||||
Standard error codes and functions to manage errors of RTI network calls.
|
||||
The error codes had better be unique values!
|
||||
*/
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
Used to set the global errno to a no error state before
|
||||
the connection failed callback is called, if the reason the callback was
|
||||
called because of a non OS failure.
|
||||
*/
|
||||
#define RTI_NETIO_NOERROR (0)
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
Error has occurred in the call. RtiNetioErrnoGet() may return specific
|
||||
causes for the failure.
|
||||
|
||||
@see RtiNetioErrnoGet
|
||||
*/
|
||||
#define RTI_NETIO_ERROR (-1)
|
||||
#define RTI_NETIO_PORT_INVALID (0)
|
||||
#define RTI_NETIO_HOST_IP_INVALID (0)
|
||||
|
||||
#if defined(RTI_UNIX)
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
/*e \ingroup rtiNetIO
|
||||
This is not a socket. The functions to operate on sockets will fail.
|
||||
*/
|
||||
#define RTI_NETIO_SOCKET_INVALID (-1)
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
Get the last error code set. To make sure you are not reading an
|
||||
error code corresponding to a previous call, set the error code to
|
||||
RTI_NETIO_NOERROR because making a netio call. This call is not
|
||||
thread-safe on some OSes at the moment.
|
||||
|
||||
@see RtiNetioErrnoSet RTI_NETIO_NOERROR
|
||||
*/
|
||||
#define RtiNetioErrnoGet() errno
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
Set the system level error code.
|
||||
|
||||
@param ErrorNumber Error code.
|
||||
|
||||
@see RtiNetioErrnoGet
|
||||
*/
|
||||
#define RtiNetioErrnoSet(ErrorNumber) {errno = ErrorNumber;}
|
||||
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
Valid option values to RtiSetSockOpt(RTI_NETIO_MULTICAST_LOOPBACK) are:
|
||||
|
||||
- RTI_NETIO_MULTICAST_LOOPBACK_ON: Turn on loopback copy for
|
||||
multicast packets. This is the default.
|
||||
- RTI_NETIO_MULTICAST_LOOPBACK_OFF Turn off loopback copy for
|
||||
multicast packets. The node may not receive any multicast
|
||||
packets sent from itself if you turn this off. This option will
|
||||
quiet unnecessary network traffic for certain applications.
|
||||
|
||||
@see RTI_NETIO_MULTICAST_LOOPBACK
|
||||
*/
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
Valid option values to RtiSetSockOpt(RTI_NETIO_BROADCAST) are:
|
||||
|
||||
- RTI_NETIO_BROADCAST_ON: Enable broadcast on the *dgram* socket.
|
||||
|
||||
- RTI_NETIO_BROADCAST_OFF Disable broadcast on the *dgram*
|
||||
socket. This is the default.
|
||||
|
||||
@see RTI_NETIO_BROADCAST
|
||||
*/
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
OS independent datatype for socket.
|
||||
*/
|
||||
typedef int RTINetioSocket;
|
||||
/*e \ingroup rtiNetio
|
||||
OS independent datatype for time-to-live value for IP packets.
|
||||
*/
|
||||
typedef unsigned char RTINetioTTL;
|
||||
|
||||
|
||||
#elif defined(RTI_VXWORKS)
|
||||
|
||||
#include <netinet/in.h>
|
||||
typedef int RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID -1
|
||||
#define RtiNetioErrnoSet(ErrorNumber) { errno = ErrorNumber; }
|
||||
#define RtiNetioErrnoGet() errno
|
||||
|
||||
|
||||
#elif defined(RTI_PSOS)
|
||||
|
||||
#include <pna.h>
|
||||
#include <errno.h>
|
||||
typedef int RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
typedef unsigned char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID (-1)
|
||||
#define RtiNetioErrnoGet() errno
|
||||
#define RtiNetioErrnoSet(ErrorNumber) { errno = ErrorNumber; }
|
||||
|
||||
#elif defined(RTI_NETOS)
|
||||
|
||||
typedef long RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID (-1)
|
||||
|
||||
|
||||
#elif defined(RTI_LYNX)
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
typedef int RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID (-1)
|
||||
#define RtiNetioErrnoGet() errno
|
||||
#define RtiNetioErrnoSet(ErrorNumber) {errno = ErrorNumber;}
|
||||
|
||||
#elif defined(RTI_QNX)
|
||||
|
||||
#include <sys/types.h> /* u_char */
|
||||
#include <netinet/in.h>
|
||||
typedef int RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID -1
|
||||
#define RtiNetioErrnoSet(ErrorNumber) { errno = ErrorNumber; }
|
||||
#define RtiNetioErrnoGet() errno
|
||||
|
||||
#elif defined(RTI_INTY)
|
||||
|
||||
//#include <INTEGRITY.h>
|
||||
#include <sys/types.h> /* u_char */
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h> /* gethostbyname */
|
||||
typedef int RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID -1
|
||||
#define RtiNetioErrnoSet(ErrorNumber) { errno = ErrorNumber; }
|
||||
#define RtiNetioErrnoGet() errno
|
||||
|
||||
|
||||
#elif defined(RTI_OPENVMS)
|
||||
#include <types.h>
|
||||
#include <tcp.h> /* for the u_* types */
|
||||
#include <errno.h>
|
||||
#include <in.h>
|
||||
typedef int RTINetioSocket;
|
||||
typedef unsigned char RTINetioTTL;
|
||||
|
||||
typedef u_char RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON 1
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF 0
|
||||
|
||||
typedef int RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON 1
|
||||
#define RTI_NETIO_BROADCAST_OFF 0
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID (-1)
|
||||
#define RtiNetioErrnoSet(ErrorNumber) {errno = ErrorNumber;}
|
||||
#define RtiNetioErrnoGet() errno
|
||||
|
||||
|
||||
#elif defined(RTI_WIN32) || defined(RTI_WINCE) || defined(RTI_WINCE30)
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
/* NOTE: Even though <windows.h> has #includes for winsock2.h and winsock.h,
|
||||
MFC code that include <afx.h> defines LEAN_AND_MEAN that prevents
|
||||
these files from being included. Thus, we need to force inclusion
|
||||
here.
|
||||
*/
|
||||
#if(_WIN32_WINNT >= 0x0400)
|
||||
/* To use WINSOCK2, ALL Windows Projects must define _WIN32_WINNT=0x0400
|
||||
on the preprocessor line */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
#if defined(RTI_WINCE) || defined(RTI_WINCE30)
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
typedef SOCKET RTINetioSocket;
|
||||
typedef int RTINetioTTL;
|
||||
typedef BOOL RTINetioMulticastLoopbackFlag;
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_ON TRUE
|
||||
#define RTI_NETIO_MULTICAST_LOOPBACK_OFF FALSE
|
||||
|
||||
typedef BOOL RTINetioBroadcastFlag;
|
||||
#define RTI_NETIO_BROADCAST_ON TRUE
|
||||
#define RTI_NETIO_BROADCAST_OFF FALSE
|
||||
|
||||
#define RTI_NETIO_SOCKET_INVALID INVALID_SOCKET
|
||||
#define RtiNetioErrnoGet() (WSAGetLastError())
|
||||
#define RtiNetioErrnoSet(ErrorNumber) WSASetLastError(ErrorNumber)
|
||||
|
||||
#ifndef EPFNOSUPPORT
|
||||
#define EPFNOSUPPORT WSAEPFNOSUPPORT
|
||||
#endif
|
||||
#ifndef ENOTSOCK
|
||||
#define ENOTSOCK WSAENOTSOCK
|
||||
#endif
|
||||
#ifndef EADDRINUSE
|
||||
#define EADDRINUSE WSAEADDRINUSE
|
||||
#endif
|
||||
#ifndef EINTR
|
||||
#define EINTR WSAEINTR
|
||||
#endif
|
||||
#ifndef EWOULDBLOCK
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#endif
|
||||
#ifndef EISCONN
|
||||
#define EISCONN WSAEISCONN
|
||||
#endif
|
||||
#ifndef EALREADY
|
||||
#define EALREADY WSAEALREADY
|
||||
#endif
|
||||
#ifndef EINPROGRESS
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#endif
|
||||
#ifndef ECONNREFUSED
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#endif
|
||||
#ifndef EMSGSIZE
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
#error "Need to port"
|
||||
#endif
|
||||
|
||||
#ifndef rti_types_h
|
||||
#include "rtilib/rti_types.h"
|
||||
#endif
|
||||
#ifndef rti_syserr_h
|
||||
#include "rtilib/rti_syserr.h"
|
||||
#endif
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
Specify either blocking or nonblocking when calling RtiNetioSetSockOpt()
|
||||
with RTI_NETIO_BLOCK option.
|
||||
|
||||
@see RtiSetSockOpt
|
||||
*/
|
||||
enum RTINetioBlockingType {
|
||||
/** If RtiSetSockOpt(RTI_NETIO_BLOCK) operation failed, the errno will be set to this. */
|
||||
RTI_NETIO_BLOCKING_ERROR = -1,
|
||||
/** Read operation will come back right away. */
|
||||
RTI_NETIO_NONBLOCKING = 0,
|
||||
/** Block on the socket until data is received. */
|
||||
RTI_NETIO_BLOCKING = 1
|
||||
};
|
||||
typedef enum RTINetioBlockingType RTINetioBlockingType;
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
OS independent abstraction for all socket options RTI programs may use.
|
||||
The following is the list of all supported socket options. Values are
|
||||
bit-specific so that we can pass 1 option value with all desired options
|
||||
at once.
|
||||
|
||||
@see RtiNetioSetSockOpt RtiNetioGetSockOpt
|
||||
*/
|
||||
enum RTINetioSocketOption {
|
||||
/** Use the default socket state. */
|
||||
RTI_NETIO_DEFAULT_OPTION = 0x0,
|
||||
/** Allow multiple sockets to bind to the same port.
|
||||
@see RtiConnectBind */
|
||||
RTI_NETIO_REUSEPORT = 0x1,
|
||||
/** Specify the size of the send buffer for the socket. Both the default
|
||||
and the maximum are OS dependent. */
|
||||
RTI_NETIO_SENDBUF = 0x2,
|
||||
/** Specify the size of the recv buffer for the socket. Both the default
|
||||
and the maximum are OS dependent. */
|
||||
RTI_NETIO_RECVBUF = 0x4,
|
||||
/** Leave a multicast group. As far as we know, this is not necessary
|
||||
if you are going to destroy the socket, coz OS automatically takes
|
||||
care of it. */
|
||||
RTI_NETIO_DROP_MEMBERSHIP = 0x8,
|
||||
/** Join a multicast group. Make sure you don't join a reserved
|
||||
multicast address! */
|
||||
RTI_NETIO_ADD_MEMBERSHIP = 0x10,
|
||||
/** Specify the maximum number of hops for the multicast packets out of
|
||||
this socket.
|
||||
@see RTINetioTTL */
|
||||
RTI_NETIO_MULTICAST_TTL = 0x20,
|
||||
/** Specify the outgoing interfaces for the multicast packets out of this
|
||||
socket. By default, packets go out on the "primary" interface,
|
||||
whatever that may be. */
|
||||
RTI_NETIO_MULTICAST_IF = 0x40,
|
||||
/** Turn on/off the loopback capability of the stack for multicast packets
|
||||
out of this socket. By default, the stack copies the multicast
|
||||
packets to loopback interface if there is an application on the local
|
||||
node that wants to receive data for that multicast address and port.
|
||||
Turning the loopback off can spare the stack from doing a lot of work,
|
||||
but you must be certain that the application does not need to receive
|
||||
that data, because the data may not even be received on the interface,
|
||||
depending on the OS. Not all OSes support this option. */
|
||||
RTI_NETIO_MULTICAST_LOOPBACK = 0x80,
|
||||
/** Turn on/off the blocking mode of this socket. */
|
||||
RTI_NETIO_BLOCK = 0x100,
|
||||
/** Turn off the use of collision-avoidance algorithm. */
|
||||
RTI_NETIO_TCP_NODELAY = 0x200,
|
||||
/** Enable/disable the broadcasting from a dgram socket. */
|
||||
RTI_NETIO_BROADCAST = 0x400,
|
||||
/** Enables linger on close if data is present */
|
||||
RTI_NETIO_LINGER = 0x800
|
||||
};
|
||||
typedef enum RTINetioSocketOption RTINetioSocketOption;
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
OS independent datatype for IP address.
|
||||
|
||||
We always use host byte order when
|
||||
interfacing with the user, and the network byte order on the wire and
|
||||
for internal representation.
|
||||
|
||||
This better be a 32 bit quantity because we need to call the
|
||||
ntohl() and htonl() macros on these integers and these macros assume
|
||||
32 bits of storage...
|
||||
I already got burn by the ALPHA architecture because I was using
|
||||
unsigned long (64 bits).
|
||||
*/
|
||||
typedef unsigned int RTINetioHostIP;
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
OS independent pseudo-object to wrap socket related data and function
|
||||
pointers.
|
||||
@see RtiNetioAddrNew RtiNetioAddrInitialize RtiNetioAddrDelete
|
||||
*/
|
||||
typedef struct RTINetioAddr RTINetioAddr;
|
||||
|
||||
typedef struct RTINetioAddrObject {
|
||||
struct sockaddr_in netioAddr;
|
||||
} RTINetioAddrObject;
|
||||
|
||||
struct RTINetioAddr {
|
||||
struct RTINetioAddrObject *pvt;
|
||||
|
||||
RTIBool (*AddressByNameSet)(RTINetioAddr *, const char *hostname,
|
||||
int portNum);
|
||||
RTIBool (*AddressByIPSet)(RTINetioAddr *, RTINetioHostIP hostIP,
|
||||
int portNum);
|
||||
RTIBool (*HostNameGet)(RTINetioAddr *, char *hostname);
|
||||
int (*PortGet)(RTINetioAddr *);
|
||||
void (*PortSet)(RTINetioAddr *, int port);
|
||||
RTINetioHostIP (*IPAddrGet)(RTINetioAddr *);
|
||||
};
|
||||
|
||||
|
||||
extern void RtiNetioVerbositySet(int level);
|
||||
|
||||
|
||||
extern int RtiNetioAddrObjCheck(RTINetioAddr *Addr);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
@brief Initialize and query avaliability of Netio transport
|
||||
|
||||
This function can be used to query the availability of a netio transport
|
||||
(currently only NETIO_IP), and initialize that implementation.
|
||||
|
||||
The function will return RTI_TRUE if successful, RTI_FALSE if the requested
|
||||
transport is not available, or the initialization was unsucessful.
|
||||
|
||||
This function must be called at least onece before any other netio
|
||||
functions; it is idempotent so that it can be called multiple times
|
||||
without side effects.
|
||||
*/
|
||||
RTIBool RtiNetioInit(void);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
@brief Cleanup state of Netio package (WindowsNT/pSOS only)
|
||||
|
||||
This function is only needed in WindowsNT applications. Call it
|
||||
after all use of the Netio package has completed. This function is
|
||||
also needed in pSOS for shutting down the socket manager
|
||||
*/
|
||||
void RtiNetioCleanup(void);
|
||||
|
||||
|
||||
#if defined(RTI_UNIX)
|
||||
# include <sys/socket.h> /* for socklen_t on solaris */
|
||||
#elif defined(RTI_WIN32)
|
||||
/* win32 is missing this posix type */
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
Behave like UNIX ioctl() on a socket.
|
||||
|
||||
Hides WinSock ioctlsocket() and presents the same interface as UNIXs ioctl().
|
||||
Always returns NETIO_ERROR on OS's that do not have a call equivalent
|
||||
to a UNIX ioctl (e.g. NetOS).
|
||||
|
||||
@param sd A operating system socket.
|
||||
@param request The option to set.
|
||||
@param total Data associated with the request type passed to the OS.
|
||||
|
||||
@return Returns int just like ioctl() and ioctlsocket(). Please note that
|
||||
the return code is OS-specific. Returns NETIO_ERROR when the underlying OS
|
||||
has no UNIX-like ioctl.
|
||||
*/
|
||||
int RtiNetioIoctl(RTINetioSocket sd, int request, int *total);
|
||||
|
||||
extern DllExport
|
||||
/*i \ingroup rtiNetio
|
||||
Set socket/file descriptor to non-blocking.
|
||||
|
||||
Use notBlocking = 0 for Blocking notBlocking = 1 for Non-Blocking
|
||||
|
||||
@param df Operating system socket.
|
||||
@param Blocking To set socket to either blocking or non-blocking.
|
||||
|
||||
@see NetioBlockingType
|
||||
*/
|
||||
int RtiNetioSocketBlockingSet(RTINetioSocket fd,
|
||||
RTINetioBlockingType Blocking);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
OS independent function to get socket option.
|
||||
|
||||
@param s Socket
|
||||
@param optType Desired action.
|
||||
@param optVal Pointer to the desired value corresponding to the optType.
|
||||
@param optLenPtr Pointer to the integer to return the actual value. Don't
|
||||
set the initial value to 0!
|
||||
|
||||
@return 0 if successful, -1 if error
|
||||
|
||||
@see RTINetioSocketOption RtiSetSockOpt
|
||||
*/
|
||||
int RtiGetSockOpt(RTINetioSocket s,
|
||||
RTINetioSocketOption optType,
|
||||
char *optVal, socklen_t *optLenPtr);
|
||||
|
||||
extern DllExport
|
||||
/*i \ingroup rtiNetio
|
||||
OS independent function to setsocket option.
|
||||
|
||||
@param s Socket
|
||||
@param optType Desired action.
|
||||
@param optVal Pointer to the desired value corresponding to the optType.
|
||||
@param optLen Length of the optVal in bytes.
|
||||
|
||||
@return 0 if successful, -1 if error
|
||||
|
||||
@see RtiGetSockOpt RTINetioSocketOption
|
||||
*/
|
||||
int RtiSetSockOpt(RTINetioSocket s,
|
||||
RTINetioSocketOption optType,
|
||||
const char *optVal, int optLen);
|
||||
|
||||
extern DllExport
|
||||
void RtiNetioSocketClose(RTINetioSocket sd);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
Set the pointers for the addr passed in, which has been pre-allocated.
|
||||
Use this if don't want to derive from RTINetioAddr struct.
|
||||
|
||||
@param addr Must not be NULL.
|
||||
|
||||
@return RTI_TRUE on success. RTI_FALSE on failure.
|
||||
|
||||
@see RtiNetioAddrNew
|
||||
*/
|
||||
RTIBool RtiNetioAddrInitialize(RTINetioAddr *addr);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
Releases the resources gathered during RtiNetioAddrInitialize().
|
||||
The only difference between this function and RtiNetioAddrDelete is that
|
||||
this does not free the RTINetioAddr itself.
|
||||
*/
|
||||
void RtiNetioAddrRelease(RTINetioAddr *addr);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
Destroys new NetioAddr. Counterpart to RtiNetioAddrNew.
|
||||
|
||||
@see RtiNetioAddrNew RtiNetioAddrRelease
|
||||
*/
|
||||
void RtiNetioAddrDelete(RTINetioAddr *addr);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiNetio
|
||||
Create a new RTINetioAddr. Will call malloc.
|
||||
|
||||
@return NULL on failure.
|
||||
|
||||
@see RtiNetioAddrInitialize
|
||||
*/
|
||||
RTINetioAddr *RtiNetioAddrNew(void);
|
||||
|
||||
extern DllExport
|
||||
int RtiConnectBind(RTINetioSocket sd, struct sockaddr_in *sockAddr,
|
||||
int portnum);
|
||||
|
||||
extern DllExport RTIBool NativeAddressSet(struct sockaddr_in *sockAddr,
|
||||
const char *hostName, int portnum,
|
||||
const char *warnPre);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_ip_h */
|
||||
@@ -0,0 +1,93 @@
|
||||
/* rti_mutex.h - built from: rti_mutex.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_mutex_h
|
||||
#define rti_mutex_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#include <rtilib/rti_types.h>
|
||||
|
||||
typedef struct RTIMutexTag *RTIMutex;
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiMutex
|
||||
|
||||
@brief Deletes a mutex.
|
||||
|
||||
Invalidates any mutex handles and removes the mutex from the system.
|
||||
|
||||
@param mutex mutex handle. Must not be NULL.
|
||||
@return RTI_TRUE on success. RTI_FALSE otherwise.
|
||||
@see RtiMutexNew
|
||||
*/
|
||||
RTIBool RtiMutexDelete(RTIMutex mutex);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiMutex
|
||||
|
||||
@brief Creates a recursive mutex.
|
||||
|
||||
The RtiMutexNew function does not give default ownership to
|
||||
the thread creating the mutex.
|
||||
|
||||
@return RTIMutex if the mutex on successful creation. Otherwise NULL.
|
||||
@see RtiMutexDelete RtiMutexTake RtiMutexGive
|
||||
*/
|
||||
RTIMutex RtiMutexNew(void);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiMutex
|
||||
|
||||
@brief Takes (gains ownership) of the mutex.
|
||||
|
||||
This function tries to gain ownership of the mutex and returns RTI_TRUE
|
||||
if it succeeds.
|
||||
|
||||
In case the mutex is already owned by another thread, the current
|
||||
thread waits indefinetely for the thread owning the mutex to give up
|
||||
ownership. The option of timeouts have not been used.
|
||||
|
||||
A thread owning the mutex can recursively take the mutex any number of
|
||||
times, but has to give the mutex the same number of times in order to give
|
||||
up ownership. Some OSes have built-in support for recursive take, while
|
||||
for others, support has been provided with the help of the mutexCount
|
||||
and thread id.
|
||||
|
||||
The default OS scheduling is used in giving ownership of the
|
||||
mutex to threads waiting on it is FIFO.
|
||||
|
||||
@param mutex RTIMutex. Must not be NULL.
|
||||
@return RTI_TRUE if the mutex was taken successfully.
|
||||
*/
|
||||
RTIBool RtiMutexTake(RTIMutex mutex);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiMutex
|
||||
|
||||
@brief Gives (relinquishes ownership of) the mutex.
|
||||
|
||||
A mutex can only be given by a thread that has taken it.
|
||||
A thread that has taken the mutex recursively has to give it the same
|
||||
number of tiems in order to completely give up ownership of the mutex
|
||||
to soem other thread waiting on it.
|
||||
|
||||
@param mutex RTIMutex. Must not be NULL.
|
||||
|
||||
@return RTI_TRUE if the mutex was given successfully.
|
||||
*/
|
||||
RTIBool RtiMutexGive(RTIMutex mutex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_mutex_h */
|
||||
@@ -0,0 +1,588 @@
|
||||
/* rti_osapi.h - built from: common.c, osapiVerbosity.c
|
||||
, sleep.c
|
||||
, thread_common.c
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_osapi_h
|
||||
#define rti_osapi_h
|
||||
|
||||
|
||||
#if !defined(rti_types_h)
|
||||
# include "rtilib/rti_types.h"
|
||||
#endif
|
||||
#if !defined(rti_mutex_h)
|
||||
# include "rtilib/rti_mutex.h"
|
||||
#endif
|
||||
#if !defined(rti_semaphore_h)
|
||||
# include "rtilib/rti_semaphore.h"
|
||||
#endif
|
||||
#if !defined(rti_time_h)
|
||||
# include "rtilib/rti_time.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*e \ingroup osapi
|
||||
|
||||
@brief Sets the verbosity of the OS API.
|
||||
|
||||
The OS api supports four verbosity levels ranging from -1 to 3.
|
||||
The verbosity level -1 suppresses all verbosity output. The other levels
|
||||
provide an increasing amount of verbosity information.
|
||||
|
||||
@param newVerbosity The new verbosity level.
|
||||
|
||||
@return Returns the previous verbosity level.
|
||||
*/
|
||||
extern int RtiOsapiVerbositySet(int newVerbosity);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Suspend current thread, sleep for specified seconds and nanoseconds.
|
||||
|
||||
This call suspends the curernt thread for the specified duration.
|
||||
Note that the granularity, and minimum sleep time are OS dependant.
|
||||
|
||||
- \b On \b VxWorks, this function calls taskDelay(),
|
||||
hence the granularity and the minimum sleep time are a
|
||||
single clock tick (as reported by sysClockRateGet()).
|
||||
- \b On \b pSOS, this function calls tm_wkafter(); the granularity is
|
||||
determined by the clock-tick rate.
|
||||
- \b On \b Unix, this function calls either poll() or select().
|
||||
In fact it may call them multiple times if poll()/select()
|
||||
return prematurely woken by a signal. RtiThreadSleep() keeps
|
||||
track of the total time slept using gettimeofday() to ensure
|
||||
the specified usec have elapsed.
|
||||
- \b On \b Win32, use Sleep(), which has a different granularity
|
||||
on different windows OSes, but is generally poorer than 10 ms.
|
||||
|
||||
\b Example:
|
||||
|
||||
To sleep for 1.5 seconds,
|
||||
\verbatim
|
||||
RTINtpTime time = RtiNtpTimePackFromMillisecr(time, 1, 500);
|
||||
RtiThreadSleep(&time);
|
||||
\endverbatim
|
||||
|
||||
@param time The amount of time to sleep using RTITime. If NULL
|
||||
(infinite time), sleep forever (on UNIX a very long time).
|
||||
If Zero time, it causes a at least a context switch.
|
||||
@return RTI_FALSE if error occurred, otherwise, return RTI_TRUE.
|
||||
*/
|
||||
RTIBool RtiThreadSleep(const RTINtpTime *time);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef rti_types_h
|
||||
#include "rtilib/rti_types.h"
|
||||
#endif
|
||||
|
||||
/* defines */
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
Parameter passed to thread creation routine. Value set
|
||||
using RTI_THREAD option macros
|
||||
*/
|
||||
typedef int RTIThreadOptions;
|
||||
/*e \ingroup rtiThread
|
||||
Use only the default options the OS gives you.
|
||||
*/
|
||||
#define RTI_THREAD_DEFAULT_OPTIONS 0x00
|
||||
/*e \ingroup rtiThread
|
||||
Support floating point.
|
||||
*/
|
||||
#define RTI_THREAD_FLOATING_POINT 0x01
|
||||
/*e \ingroup rtiThread
|
||||
This thread can do standard io.
|
||||
*/
|
||||
#define RTI_THREAD_STDIO 0x02
|
||||
/*e \ingroup rtiThread
|
||||
This thread will run in real-time priority mode.
|
||||
*/
|
||||
#define RTI_THREAD_REALTIME_PRIORITY 0x08
|
||||
/*e \ingroup rtiThread
|
||||
Insist on the specified priority and fail if OS doesn't like it.
|
||||
*/
|
||||
#define RTI_THREAD_PRIORITY_ENFORCE 0x10
|
||||
/*e \ingroup rtiThread
|
||||
Set the flag to be able to asynchronously cancel thread.
|
||||
*/
|
||||
#define RTI_THREAD_CANCEL_ASYNCHRONOUS 0x20
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
The return status of thread functions.
|
||||
*/
|
||||
typedef int RTIThreadRtnStatus;
|
||||
/*e \ingroup rtiThread
|
||||
Function success.
|
||||
*/
|
||||
#define RTI_THREAD_OK (0)
|
||||
/*e \ingroup rtiThread
|
||||
Function error.
|
||||
*/
|
||||
#define RTI_THREAD_ERROR (-1)
|
||||
/*e \ingroup rtiThread
|
||||
Function called on a non-threaded OS
|
||||
*/
|
||||
#define RTI_THREAD_NOT_SUPPORTED (-2)
|
||||
|
||||
/*e \defgroup RTIThreadProperty
|
||||
\ingroup rtiThread
|
||||
@see RtiThreadCreate
|
||||
*/
|
||||
struct RTIThreadProperty {
|
||||
int priority;
|
||||
int stackSize;
|
||||
int options;
|
||||
};
|
||||
|
||||
/*e \ingroup RTIThreadProperty */
|
||||
#define RTI_THREAD_PROPERTY_DEFAULT { \
|
||||
RTI_THREAD_DEFAULT_PRIORITY, \
|
||||
RTI_THREAD_DEFAULT_STACKSIZE, \
|
||||
RTI_THREAD_PRIORITY_ENFORCE | RTI_THREAD_STDIO}
|
||||
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Function prototype for entry point for the thread.
|
||||
|
||||
Function prototype for the routine specified at thread creation
|
||||
time. The new thread will start executing this function.
|
||||
|
||||
@param threadParam Pointer to data that will be passed to the thread
|
||||
routine. You must cast this to appropriate type to access the data.
|
||||
*/
|
||||
typedef void *(*RTIThreadStartRtn)(void *threadParam);
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Opaque pointer to hide rti thread object.
|
||||
|
||||
RTIThreadIdTag contains OS dependent fields. Exposing this would entail
|
||||
pulling in different header files for different OS to resolve the symbols.
|
||||
Using opaque handle lets us hide such headache.
|
||||
*/
|
||||
typedef struct RTIThreadIdTag *RTIThreadId;
|
||||
|
||||
typedef struct RTISystemThreadInfo {
|
||||
RTIBool realtimeEnabled;
|
||||
int policy;
|
||||
int realtime_priority_max;
|
||||
int realtime_priority_min;
|
||||
int normal_priority_max;
|
||||
int normal_priority_min;
|
||||
int rt_id; /* class id for real-time scheduling */
|
||||
int ts_id; /* class id for time-share scheduling */
|
||||
} RTISystemThreadInfo;
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Refer to itself.
|
||||
|
||||
This is what an RTI thread calls itself, instead of "Mi" (ala The
|
||||
Sound of Music).
|
||||
|
||||
*/
|
||||
#define RTI_THREAD_ID_SELF ((RTIThreadId)NULL)
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
Priorities defined by RTI must be mapped to native priorities
|
||||
using RtiThreadNativePriorityGet() because you must pass a *native* thread
|
||||
priority to RtiThreadCreate()
|
||||
*/
|
||||
#define RTI_THREAD_PRIORITY_INVALID (-8998998)
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
A convenient constant for the minimum priority. This is a logical number,
|
||||
and has to be mapped to the actual OS minimum priority.
|
||||
*/
|
||||
#define RTI_THREAD_PRIORITY_MIN (0)
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
A convenient constant for the maximum priority. This is a logical number,
|
||||
and has to be mapped to the actual OS maximum priority.
|
||||
*/
|
||||
#define RTI_THREAD_PRIORITY_MAX (255)
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
A convenient constant for the default thread priority on any
|
||||
OS. The actual values differ, of course.
|
||||
*/
|
||||
#if defined(RTI_VXWORKS) || defined (RTI_PSOS)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (100)
|
||||
#elif defined(RTI_LYNX)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (17)
|
||||
#elif defined(RTI_NETOS)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (15)
|
||||
#elif defined(RTI_WIN32)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (0)
|
||||
#elif defined(RTI_WINCE) || defined(RTI_WINCE30)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (251)
|
||||
#elif defined(RTI_QNX)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (10)
|
||||
#elif defined(RTI_INTY)
|
||||
/* INTEGRITY-include/sched.h mentions 16. The maximum
|
||||
thread priority in a virtual address space seems to be 127
|
||||
(based on pthread_getschedparam). */
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (16)
|
||||
#elif defined(RTI_OPENVMS)
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (11)
|
||||
#else
|
||||
#define RTI_THREAD_DEFAULT_PRIORITY (-9999999)
|
||||
#endif
|
||||
|
||||
/*e \ingroup rtiThread
|
||||
A convenient constant for the default thread stack size on any OS.
|
||||
The actual values differ, of course.
|
||||
*/
|
||||
#ifdef RTI_VXWORKS
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (16*1024)
|
||||
#elif defined(RTI_PSOS)
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (16*1024)
|
||||
#elif defined(RTI_NETOS)
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (16*1024)
|
||||
/* windows ignores specifying the desired stack size */
|
||||
#elif defined(RTI_WIN32) || defined(RTI_WINCE) || defined(RTI_WINCE30)
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (0)
|
||||
#elif defined(RTI_LYNX)
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (16*1024)
|
||||
#elif defined(RTI_QNX)
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (16*1024)
|
||||
#elif defined(RTI_INTY)
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (20*1024)
|
||||
#else
|
||||
/* use OS default value */
|
||||
#define RTI_THREAD_DEFAULT_STACKSIZE (-1)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Create a new thread.
|
||||
|
||||
Creates a new thread with the specified priority and
|
||||
stack size. The new thread starts executing the "thread_rtn" which gets
|
||||
passed the single parameter "param".
|
||||
The thread is removed when the function "thread_rtn" returns.
|
||||
|
||||
The function returns a newly allocated ThreadId. It is the
|
||||
responsibility of the user of this method to free this structure again
|
||||
with RtiThreadIdDelete (see the example below).
|
||||
|
||||
The priority passed to RtiThreadCreate() is the *native* OS priority.
|
||||
You can use RtiThreadNativePriorityGet() to get a native priority from
|
||||
a system-independent logical priority.
|
||||
|
||||
NOTE: By default this function does not check whether the
|
||||
specified priority is in the allowed range for the OS/Mode where the
|
||||
process is running. If it is not in range, you will get
|
||||
whatever the OS decides to give you. To get predictable behavior,
|
||||
you must specify the RTI_THREAD_PRIORITY_ENFORCE flag in your
|
||||
options parameter. When this option is specified, RtiTreadCreate()
|
||||
will check the priority, and return NULL *nwithout* starting
|
||||
the thread if the priority is outside the allowed range.
|
||||
|
||||
Hence you should *always* use RTI_THREAD_PRIORITY_ENFORCE. The only
|
||||
reason this is not the default is to provide backwards compatibility.
|
||||
|
||||
Note on IRIX native sprocs:
|
||||
|
||||
Priorities from NDPHIMAX (30) to NDPHIMIN (39) are considered real-time
|
||||
and higher than normally scheduled processes.
|
||||
|
||||
You should NOT set normal priorities if don't want to degrade
|
||||
what you would get if didn't try to set any priorities.
|
||||
Setting a normal priority will guarantee that you get something
|
||||
less than if you didn't set anything at all!
|
||||
|
||||
Note on Windows:
|
||||
|
||||
Windows supports 7 levels for threads (within each priority class -
|
||||
there are 4 priorities classes, and all
|
||||
threads within a process belong to one of these 4 classes): The actual enum
|
||||
BZ value of these macros is different on Windows, and to gain some
|
||||
commonality, the THREAD_PRIORITIES are defined as follows. (This mapping
|
||||
is done during ThreadCreate, but not with ThreadPrioritySet, there you must
|
||||
use navtive priorities)
|
||||
|
||||
- RTI_THREAD_PRIORITY_TIME_CRITICAL - 3
|
||||
- RTI_THREAD_PRIORITY_HIGHEST - 2
|
||||
- RTI_THREAD_PRIORITY_ABOVE_NORMAL - 1
|
||||
- RTI_THREAD_PRIORITY_NORMAL - 0
|
||||
- RTI_THREAD_PRIORITY_BELOW_NORMAL - -1
|
||||
- RTI_THREAD_PRIORITY_LOWEST - -2
|
||||
|
||||
On Windows:
|
||||
|
||||
THREAD_PRIORITY_IDLE - -3
|
||||
|
||||
\b Example:
|
||||
The following provide some basic examples:
|
||||
|
||||
\verbatim
|
||||
void PrintMessage(RTIThreadId tid)
|
||||
{
|
||||
char *message = (char *)RtiThreadParamGet(tid);
|
||||
printf("%s\n", message);
|
||||
}
|
||||
|
||||
RTIThreadId tid;
|
||||
tid = RtiThreadCreate("WelcomeThread", 100, RTI_THREAD_PRIORITY_ENFORCE,
|
||||
1024, PrintMessage, "Hello world", NULL);
|
||||
RtiThreadIdDelete(tid);
|
||||
\endverbatim
|
||||
|
||||
@param name The name of the thread.
|
||||
@param priority The operating system specific priority.
|
||||
@param options Thread options.
|
||||
@param thread_rtn The starting location of this new thread.
|
||||
|
||||
@return On failure, this function returns NULL. On sucess, this function
|
||||
returns a handle to a new ThreadId.
|
||||
|
||||
@see RtiThreadParamGet RtiThreadIdDelete
|
||||
*/
|
||||
RTIThreadId RtiThreadCreate(const char *name, int priority,
|
||||
RTIThreadOptions options,
|
||||
size_t stackSize, RTIThreadStartRtn thread_rtn,
|
||||
void *threadParam);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Terminates a thread.
|
||||
|
||||
This function should be avoided if at all possible. Most operating systems
|
||||
do not cleanup resources if a thread has been terminated.
|
||||
*/
|
||||
RTIBool RtiThreadTerminate(RTIThreadId tid);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Set the priority of the native thread with a native priority.
|
||||
|
||||
This function sets the priority of the thread that is represented by the
|
||||
ThreadId. The priority specified is that of the native priority and not
|
||||
our logical thread priority. If you pass RTI_THREAD_ID_SELF then the
|
||||
priority will be changed on the calling thread.
|
||||
|
||||
@param tid A thread handle.
|
||||
|
||||
@return On success, this function returns RTI_TRUE indicating that
|
||||
the thread has a new priority. On failure, this function returns
|
||||
RTI_FALSE. Most likely the calling thread does not have permission
|
||||
to set the priority of the child.
|
||||
*/
|
||||
RTIBool RtiThreadPrioritySet(RTIThreadId tid, int priority);
|
||||
|
||||
extern DllExport
|
||||
/*e rtiThread
|
||||
|
||||
@brief Returns the native priority of the native thread.
|
||||
|
||||
This function retursn the priority of the thread that is represented by
|
||||
the ThreadId. The priority returned is a native priority and not our
|
||||
logical thread priority. If you pass RTI_THREAD_ID_SELF then the
|
||||
priority will be from the calling thread.
|
||||
|
||||
@param tid A thread handle.
|
||||
|
||||
@return On success, this function returns RTI_TRUE and the parameter
|
||||
priority contains the tid's native priority. On failure,
|
||||
this function return RTI_FALSE indicating that the calling thread
|
||||
doesn't have permission to get the priority of the child or the
|
||||
thread handle is no longer valid.
|
||||
*/
|
||||
RTIBool RtiThreadPriorityGet(RTIThreadId tid, int *priority);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtithread
|
||||
|
||||
@brief Delete a thread.
|
||||
|
||||
Frees the memory associates with the ThreadId.
|
||||
|
||||
@param tid A handle to the thread to delete.
|
||||
*/
|
||||
void RtiThreadIdDelete(RTIThreadId tid);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Exits the current thread.
|
||||
*/
|
||||
void RtiThreadExit(void);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Get an unique id for the thread.
|
||||
|
||||
Gets an unique task ID.
|
||||
|
||||
You can use tid==NULL to get the Unique Id. for the calling thread,
|
||||
but it the thread has access to its own ThreadId, is more efficient to
|
||||
call RtiThreadUniqueIdGet() using a non-NULL tid.
|
||||
|
||||
@param tid The thread handle.
|
||||
*/
|
||||
unsigned long RtiThreadSelfIdGet(void);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Get the name of a thread.
|
||||
@see RtiThreadCreate RTI_THREAD_ID_SELF
|
||||
*/
|
||||
const char *RtiThreadNameGet(RTIThreadId tid);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Returns the options of the spawned child.
|
||||
|
||||
These are the options specified during creation.
|
||||
|
||||
@param tid A thread handle.
|
||||
@return Returns a bit mask of thread options.
|
||||
*/
|
||||
RTIThreadOptions RTIThreadOptionsGet(RTIThreadId tid);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Gets the threadParam parameter passed to RtiThreadCreate.
|
||||
|
||||
@param tid A Thread handle.
|
||||
@see RtiThreadCreate
|
||||
*/
|
||||
void *RtiThreadParamGet(RTIThreadId tid);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Gets the OS handle for this thread.
|
||||
|
||||
Return the underlying's OS handel for the thread. The result must
|
||||
be cast to the type appropriate for each OS. For instance
|
||||
|
||||
\verbatim
|
||||
VxWorks: int osTid = (int)RtiThreadNativeOSHandleGet(tid);
|
||||
POSIX: pthread_t osTid = (pthread_t)tid;
|
||||
Solaris: thread_t osTid = (thread_t)tid;
|
||||
Win32: HANDLE osTid = (HANDLE)tid;
|
||||
\endverbatim
|
||||
|
||||
@see VxWorks taskLib(2) POSIX pthread_init(2) Solaris thr_create(2)
|
||||
Win32 CreateThread(2)
|
||||
*/
|
||||
void *RtiThreadNativeOSHandleGet(RTIThreadId tid);
|
||||
|
||||
extern DllExport
|
||||
/*i \ingroup rtiThread
|
||||
|
||||
@brief Returns the acceptable range of priorities given a thread handle.
|
||||
|
||||
The acceptable range of priorities depends on the scheduling used for a
|
||||
thread. The defualt schedule depends on each operating system and
|
||||
on the thread. Since, we force a particular schedule on a thread during
|
||||
creation, it is possible for a group of threads to have different
|
||||
schedules and therfore a different range of acceptable values.
|
||||
|
||||
@param tid A thread handle (you can pass RTI_THREAD_ID_SELF).
|
||||
@param info A structure filled in with the threads acceptable range
|
||||
of priorities.
|
||||
|
||||
@return On success, this function return RTI_TRUE.
|
||||
*/
|
||||
RTIBool RtiThreadInfoGet(RTIThreadId tid, RTISystemThreadInfo *info);
|
||||
|
||||
extern DllExport
|
||||
/*i \ingroup rtiThread
|
||||
|
||||
@brief Returns system level information about threads to be created.
|
||||
|
||||
This is the information about the appropriate priorities that RTI
|
||||
wants to use when creating threads. This may differ from the actual
|
||||
accepted range of priorities.
|
||||
|
||||
@see RtiThreadInfoGet
|
||||
*/
|
||||
RTIBool RtiSystemThreadInfoGet(RTISystemThreadInfo *info);
|
||||
|
||||
extern DllExport
|
||||
/*i Initializes system thread info structure. */
|
||||
void RtiSystemThreadInfoInitialize(RTISystemThreadInfo *info);
|
||||
|
||||
extern DllExport
|
||||
/*i \ingroup rtiThread
|
||||
Prints the system information.
|
||||
*/
|
||||
void RtiSystemThreadInfoPrint(RTISystemThreadInfo *info);
|
||||
|
||||
extern DllExport
|
||||
/*i \ingroup rtiThread
|
||||
|
||||
@brief Gets the native priority for the thread.
|
||||
|
||||
RTI priority range is 0 to 255 with 255 being the highest priority.
|
||||
|
||||
Because not all OS's have 256 priority levels there may be a many to
|
||||
one mapping of RTI priorities to native priorities.
|
||||
|
||||
The mapping is linear at this time and will change depending on the
|
||||
operation mode that you are running and requesting.
|
||||
|
||||
WARNING: This performs a floating point calculation. We should change this
|
||||
soon!
|
||||
*/
|
||||
int RtiThreadNativePriorityGet(RTIThreadOptions options,
|
||||
int normalizedPriority );
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiThread
|
||||
|
||||
@brief Check if the priority is valid on this OS.
|
||||
|
||||
\b Example
|
||||
\verbatim
|
||||
if(RtiThreadPriorityOK(100, 0)) {
|
||||
RtiThreadCreate("WelcomeThread", 100, 0, 1024,
|
||||
PrintMessage, "Hello world", NULL);
|
||||
} else {
|
||||
printf("bad priority");
|
||||
}
|
||||
\endverbatim
|
||||
@param priority The priority in question.
|
||||
@param option thread option you would specify when creating the thread.
|
||||
@return RTI_TRUE if the priority is valid. RTI_FALSE otherwise.
|
||||
*/
|
||||
RTIBool RtiThreadPriorityOK(int priority, RTIThreadOptions options);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* rti_osapi_h */
|
||||
@@ -0,0 +1,236 @@
|
||||
/* rti_semaphore.h - built from: rti_semaphore_common.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_semaphore_h
|
||||
#define rti_semaphore_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(rti_time_h)
|
||||
#include "rtilib/rti_time.h"
|
||||
#endif
|
||||
|
||||
/*e \defgroup rtiSem RTISemaphore
|
||||
\ingroup osapi
|
||||
|
||||
@brief OS independent semaphore API.
|
||||
|
||||
Semaphores are different than mutex; it is a lot heavier, and is more
|
||||
than you need if you simply want to protect critical region. In such
|
||||
case, use mutex.
|
||||
|
||||
@see RTIMutex
|
||||
*/
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Opaque pointer to hide rti semaphore object.
|
||||
|
||||
RTISemaphoreIdTag contains OS dependent fields. Exposing this would entail
|
||||
pulling in different header files for different OS to resolve the symbols.
|
||||
Using opaque handle lets us hide such headache.
|
||||
*/
|
||||
typedef struct RTISemaphoreIdTag *RTISemaphoreId;
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
@brief The return status of semaphore functions.
|
||||
*/
|
||||
typedef int RTISemaphoreRtnStatus;
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
@brief Success.
|
||||
*/
|
||||
#define RTI_SEMAPHORE_OK (0)
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
@brief Failure or timeout.
|
||||
*/
|
||||
#define RTI_SEMAPHORE_ERROR (-1)
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
@brief Indicate no timeout for taking a semaphore (blocking for ever).
|
||||
*/
|
||||
#define RTI_SEMAPHORE_WAIT_FOREVER ((const RTINtpTime *)NULL)
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Initial state of the binary semaphore.
|
||||
|
||||
Indicates whether the semaphore is initially availiable (full) or
|
||||
unavailable. Both binary and mutex semaphores can be in two states:
|
||||
full or empty. If a task tries to take the semaphore and it is
|
||||
empty, the task will block until the semaphore becomes full. If a
|
||||
semaphore is empty and a task "gives" the semaphore, it then becomes
|
||||
full. Whenever a task takes the semaphore it becomes empty.
|
||||
|
||||
@see RtiSemaphoreBinaryNew RtiSemaphoreTake RtiSemaphoreGive
|
||||
*/
|
||||
enum RTISemaphoreState {
|
||||
/** The semaphore starts empty. */
|
||||
RTI_SEMAPHORE_EMPTY = 0,
|
||||
/** The semaphore starts full. */
|
||||
RTI_SEMAPHORE_FULL = 1
|
||||
};
|
||||
typedef enum RTISemaphoreState RTISemaphoreState;
|
||||
|
||||
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Semaphore options.
|
||||
|
||||
Controls the behavior of the semaphore.
|
||||
|
||||
@see RtiSemaphoreGive
|
||||
*/
|
||||
enum RTISemaphoreQOptions {
|
||||
/** The order threads are awaken is first in first out. */
|
||||
RTI_SEMAPHORE_Q_FIFO = 0x0,
|
||||
/** The order threads are awaken is determined by their priority. */
|
||||
RTI_SEMAPHORE_Q_PRIORITY = 0x1
|
||||
};
|
||||
typedef enum RTISemaphoreQOptions RTISemaphoreQOptions;
|
||||
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Creates a binary semaphore.
|
||||
|
||||
There are three types of semaphores: binary, counting and mutex.
|
||||
|
||||
Semaphores can be used for two main purposes: mutual exclusion and
|
||||
synchronization.
|
||||
|
||||
When used for mutual exclusion the semaphore starts in the full
|
||||
state. Any task that wants to access the critical section first
|
||||
aquires the semaphore, accesses the critical section and then
|
||||
releases the semaphore.
|
||||
|
||||
When used for synchronization the semaphore starts in the empty
|
||||
state, a waiting task takes it and blocks until some other tasks
|
||||
wakes up the waiting task by giving the semaphore.
|
||||
|
||||
Binary semaphores are the simplest and most efficient
|
||||
semaphores. They can be used for mutual exclusion or
|
||||
synchronization. They impose no restrictions on the tasks that take
|
||||
or give the semaphores.
|
||||
|
||||
@param options General options such as the ordering of waiting threads.
|
||||
@param initState Whether the semaphore should start empty or full.
|
||||
|
||||
@see RtiSemaphoreMutexNew RtiSemaphoreQOptions RtiSemaphoreState
|
||||
@see RtiSemaphoreTake RtiSemaphoreGive RtiSemaphoreDelete
|
||||
*/
|
||||
RTISemaphoreId RtiSemaphoreBinaryNew(RTISemaphoreQOptions options,
|
||||
RTISemaphoreState initState);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Creates a counting semaphore.
|
||||
|
||||
Counting semaphores are another menas for task synch and mutual
|
||||
exclusion. It works like binary semaphore except it keeps track of the
|
||||
number of times a semaphore is given. Every time a semaphore is given,
|
||||
the counter increments, everytime of taking, counter decrements.
|
||||
When counter reach 0, taking task blocks. Since it has a counter, it
|
||||
can be given twice and taken twice without blocking, this is different
|
||||
from binary semaphore.
|
||||
|
||||
@see RtiSemaphoreTake RtiSemaphoreGive RtiSemaphoreDelete
|
||||
*/
|
||||
RTISemaphoreId RtiSemaphoreCountingNew(RTISemaphoreQOptions options,
|
||||
unsigned int initCount);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Creates a mutex semaphore.
|
||||
|
||||
See RtiSemaphoreNew() for a description of the different types of
|
||||
semaphores.
|
||||
|
||||
Mutex semaphores are more complex (and heavy) than binary
|
||||
semaphores. They should be used only for mutual exclusion.
|
||||
|
||||
Mutex semaphores can only be given by the same task that took them
|
||||
and can be taken recursively.
|
||||
|
||||
Use sparingly. Significantly less efficient then binary semaphores.
|
||||
|
||||
@see RtiSemaphoreNew RTISemaphoreQOptions RtiSemaphoreTake RtiSemaphoreGive
|
||||
@see RtiSemaphoreDelete
|
||||
*/
|
||||
RTISemaphoreId RtiSemaphoreMutexNew(RTISemaphoreQOptions options);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Takes a semaphore (whatever the type).
|
||||
|
||||
This function tries to take a semaphore and returns RTI_SEMAPHORE_OK
|
||||
if the semaphore is taken succesfully. It returns
|
||||
RTI_SEMAPHORE_ERROR if the timeout expired before the semaphore
|
||||
could be taken or if some other problem occurred.
|
||||
|
||||
A timeout is optional: it allows the call to return before the
|
||||
semaphore is taken (with a return code of RTI_SEMAPHORE_ERROR).
|
||||
Timeouts are only supported on VxWorks, pSOS and Windows. On other
|
||||
architectures, a timeout different from 0 is equivalent to a
|
||||
RTI_SEMAPHORE_WAIT_FOREVER.
|
||||
|
||||
@param client The Semaphore ID.
|
||||
@param timeout The time to wait in seconds or RTI_SEMAPHORE_WAIT_FOREVER.
|
||||
|
||||
@see RtiSemaphoreGive
|
||||
*/
|
||||
RTISemaphoreRtnStatus RtiSemaphoreTake(RTISemaphoreId semId,
|
||||
const RTINtpTime *timeout);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
@brief Gives a semaphore.
|
||||
|
||||
|
||||
A mutex semaphore can only be given by the thread that holds the
|
||||
mutex. If RtiSemaphoreGive is called by a thread that does not hold
|
||||
the mutex, the function may (but is not forced to) return
|
||||
RTI_SEMAPHORE_ERROR. It is the responsibility of the user code to
|
||||
make sure this doesn't happen.
|
||||
|
||||
A binary semaphore can be given by any thread at any point in time.
|
||||
If the semaphore is already available, the call will not have an
|
||||
effect. In that case, the function still returns RTI_SEMAPHORE_OK.
|
||||
|
||||
@param semId semaphore
|
||||
|
||||
@see RtiSemaphoreTake
|
||||
*/
|
||||
RTISemaphoreRtnStatus RtiSemaphoreGive(RTISemaphoreId semId);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiSem
|
||||
|
||||
Destroys a semaphore. As with other semaphore functions,
|
||||
don't confuse it with mutex!
|
||||
|
||||
@param semId Either a binary or a mutex semaphore. Must not be NULL.
|
||||
|
||||
@see RtiSemaphoreNew RtiSemaphoreMutexNew
|
||||
*/
|
||||
RTISemaphoreRtnStatus RtiSemaphoreDelete(RTISemaphoreId semId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_semaphore_h */
|
||||
@@ -0,0 +1,141 @@
|
||||
/* rti_syserr.h - built from: errorapi.c, errorimpl.c
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_syserr_h
|
||||
#define rti_syserr_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(RTI_VXWORKS)
|
||||
# include <vxWorks.h> /* needed for cpu preprocessor define*/
|
||||
#endif
|
||||
#if defined(RTI_INTY)
|
||||
# include <INTEGRITY.h> /* for consolestring() */
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
#include "rtilib/rti_types.h" /* for RTIBool */
|
||||
#define RTI_MAX_MSG_SIZE 1024
|
||||
|
||||
|
||||
typedef enum {
|
||||
RTI_LOG_FORWARD,
|
||||
RTI_LOG_PRINT,
|
||||
RTI_LOG_CALLBACK_DATA,
|
||||
RTI_LOG_CALLBACK_FUNC,
|
||||
RTI_LOG_CONTEXT_FORWARD
|
||||
} RTILogHookType;
|
||||
|
||||
typedef struct {
|
||||
/* specifies a number for the log message */
|
||||
unsigned int logNumber;
|
||||
/* specifies the format of the log message */
|
||||
const char *format;
|
||||
} RTILogMsgType;
|
||||
|
||||
/* define function prototypes */
|
||||
typedef size_t (*RTIContextAndLogMsgForwardHook)(const char *context,
|
||||
const RTILogMsgType *msg,
|
||||
...);
|
||||
typedef size_t (*RTILogMsgForwardHook)(const RTILogMsgType *msg, ...);
|
||||
typedef size_t (*RTILogMsgPrintHook)(const char *msg);
|
||||
typedef void (*RTILogCallBackHook)(const RTILogMsgType *msg,
|
||||
void *userData);
|
||||
|
||||
#define RtiV0LogOutput(verbosity) if(verbosity >= 0) RtiLogOutput
|
||||
#define RtiV1LogOutput(verbosity) if(verbosity >= 1) RtiLogOutput
|
||||
#define RtiV2LogOutput(verbosity) if(verbosity >= 2) RtiLogOutput
|
||||
#define RtiV3LogOutput(verbosity) if(verbosity >= 3) RtiLogOutput
|
||||
|
||||
/* compatible with 4.1 syserr, should be removed after migration */
|
||||
#define RtiV0Warning(verbosity) if(verbosity >= 0) RtiMessage
|
||||
#define RtiV1Warning(verbosity) if(verbosity >= 1) RtiMessage
|
||||
#define RtiV2Warning(verbosity) if(verbosity >= 2) RtiMessage
|
||||
#define RtiV3Warning(verbosity) if(verbosity >= 3) RtiMessage
|
||||
|
||||
/* Bitmaps that define what gets printed */
|
||||
/* Print the log number */
|
||||
#define RTI_LOG_PRINTPROPERTIES_LOGNUMBER 0x00000001
|
||||
/* Print the log message (enabled by default) */
|
||||
#define RTI_LOG_PRINTPROPERTIES_LOGMSG 0x00000002
|
||||
|
||||
|
||||
extern DllVariable RTILogCallBackHook RtiLogCallBack;
|
||||
|
||||
extern DllVariable RTILogMsgPrintHook RtiLogMsg;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern DllExport
|
||||
size_t RtiContextAndLogPrint(const char *context,
|
||||
const RTILogMsgType *errMsg, ...);
|
||||
|
||||
extern DllExport
|
||||
size_t RtiLogPrint(const RTILogMsgType *errMsg, ...);
|
||||
|
||||
extern DllExport
|
||||
size_t RtiDebugPrint(const char *errMsg, ...);
|
||||
|
||||
|
||||
#define RtiMessage RtiDebugPrint
|
||||
#define RtiPError RtiDebugPrint
|
||||
|
||||
extern DllExport
|
||||
size_t RtiLogSNPrint(char *dst, size_t maxLen, const RTILogMsgType *errMsg, ...);
|
||||
|
||||
extern DllExport
|
||||
size_t RtiLogPrintDeprication(unsigned int logIdx,
|
||||
const char* fmt, ...);
|
||||
|
||||
extern DllVariable RTIContextAndLogMsgForwardHook RtiContextAndLogOutput;
|
||||
|
||||
extern DllVariable RTILogMsgForwardHook RtiLogOutput;
|
||||
|
||||
extern DllExport
|
||||
RTIBool RtiLogMsgHookRegister(RTILogHookType type, void *regData);
|
||||
|
||||
extern DllExport
|
||||
RTIBool RtiLogMsgHookUnRegister(RTILogHookType type);
|
||||
|
||||
extern DllExport
|
||||
void RtiLogPrintPropertiesBitmapSet(int bitmap);
|
||||
|
||||
extern DllExport
|
||||
int RtiLogPrintPropertiesBitmapGet(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern DllExport
|
||||
RTIBool RtiVerbosityFlush(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_syserr_h */
|
||||
@@ -0,0 +1,157 @@
|
||||
/* rti_tcp.h - built from: tcp.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_tcp_h
|
||||
#define rti_tcp_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef rti_ip_h /* for efficiency */
|
||||
#include "rtilib/rti_ip.h" /* coz. UDP depends on IP */
|
||||
#endif
|
||||
|
||||
/* defines */
|
||||
|
||||
typedef struct RTITcp RTITcp; /* Forward ref just to compile */
|
||||
typedef void (*RTITcpConnectFailFnc)(RTITcp *, RTINetioSocket);
|
||||
|
||||
/*e \ingroup rtiTCP
|
||||
You must specify the type of connection when you create an RTITcp object.
|
||||
- RTI_TCP_SERVER
|
||||
- RTI_TCP_CLIENT
|
||||
@see RtiTcpNew
|
||||
*/
|
||||
enum RTITcpConnectType{
|
||||
RTI_TCP_SERVER,
|
||||
RTI_TCP_CLIENT
|
||||
};
|
||||
typedef enum RTITcpConnectType RTITcpConnectType;
|
||||
|
||||
/*e \ingroup rtiTCP
|
||||
RTI_TCP_SERVER may perform the these setsockopt before attempts to bind.
|
||||
*/
|
||||
enum RTITcpSetSockOptAction {
|
||||
/** No op. */
|
||||
RTI_TCP_NOACTION = 0x00,
|
||||
/** Allow multiple programs to bind to the same port.
|
||||
Q: why not use RTI_NETIO_REUSEPORT? */
|
||||
RTI_TCP_REUSEPORT = 0x01,
|
||||
/** Disables linger on close if data is present. */
|
||||
RTI_TCP_NOLINGER = 0x02,
|
||||
/** Enables linger on close if data is present. */
|
||||
RTI_TCP_LINGER = 0x04
|
||||
};
|
||||
typedef enum RTITcpSetSockOptAction RTITcpSetSockOptAction;
|
||||
|
||||
enum RTITcpConnectStatus{
|
||||
RTI_TCP_CONNECT_OK = 0,
|
||||
RTI_TCP_CONNECT_INPROGRESS,
|
||||
RTI_TCP_CONNECT_NOTINHOSTTABLE,
|
||||
RTI_TCP_CONNECT_REFUSED,
|
||||
RTI_TCP_CONNECT_ERROR
|
||||
};
|
||||
typedef enum RTITcpConnectStatus RTITcpConnectStatus;
|
||||
|
||||
enum RTITcpPeriodType {
|
||||
RTI_TCP_CONNECT_RETRY = 0,
|
||||
RTI_TCP_READ_RETRY = 1,
|
||||
RTI_TCP_WRITE_RETRY = 2
|
||||
};
|
||||
typedef enum RTITcpPeriodType RTITcpPeriodType;
|
||||
|
||||
struct RTITcpObject;
|
||||
struct RTITcp {
|
||||
struct RTITcpObject *pvt;
|
||||
|
||||
RTITcpConnectStatus (*Connect)(RTITcp *, const char *hostname);
|
||||
void (*Close)(RTITcp *);
|
||||
RTIBool (*Write)(RTITcp *, void *data, size_t size);
|
||||
ssize_t (*Read)(RTITcp *, void *data, size_t size);
|
||||
RTIBool (*ReadBlocking)(RTITcp *, void *data, size_t size);
|
||||
int (*HasData)(RTITcp *);
|
||||
RTITcp *(*Clone)(RTITcp *);
|
||||
int (*Ioctl)(RTITcp *, int req, int *arg);
|
||||
RTINetioSocket (*DataSocketGet)(RTITcp *);
|
||||
RTINetioBlockingType (*DataBlockingGet)(RTITcp *);
|
||||
void (*DataBlockingSet)(RTITcp *, RTINetioBlockingType);
|
||||
RTINetioSocket (*ListenSocketGet)(RTITcp *);
|
||||
void (*ListenBlockingSet)(RTITcp *, RTINetioBlockingType);
|
||||
RTINetioBlockingType (*ListenBlockingGet)(RTITcp *);
|
||||
int (*RetryPeriodSet)(RTITcp *, RTITcpPeriodType,
|
||||
int usec);
|
||||
int (*PortGet)(RTITcp *);
|
||||
char *(*HostNameGet)(RTITcp *);
|
||||
RTINetioAddr *(*AddrGet)(RTITcp *);
|
||||
void (*ClientDataSet)(RTITcp *, void *param);
|
||||
void *(*ClientDataGet)(RTITcp *);
|
||||
void (*ConnectFailSet)(RTITcp *, RTITcpConnectFailFnc);
|
||||
int (*SetSockOpt)(RTITcp *,
|
||||
RTINetioSocketOption optType,
|
||||
const char *optVal, int optlen);
|
||||
ssize_t (*Writen)(RTITcp *, void *data, size_t size);
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern const char *RTITcpConnectStatusMsg[];
|
||||
|
||||
extern DllExport
|
||||
void RtiTcpVerbositySet(int level);
|
||||
|
||||
extern DllExport
|
||||
int RtiTcpObjCheck(RTITcp *T);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiTCP
|
||||
@brief Destroys a RTITcp object.
|
||||
|
||||
All open connections are closed before destruction, and all memory is freed.
|
||||
|
||||
The service is deregistered (or attempted to be deregistered) if
|
||||
deregisterService is RTI_TRUE. If the service was never registered,
|
||||
this flag is moot.
|
||||
|
||||
@param tcp
|
||||
The RTITcp object to destroy.
|
||||
*/
|
||||
void RtiTcpDelete(RTITcp *tcp);
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiTCP
|
||||
@brief Creates a Tcp object.
|
||||
|
||||
@param serverOrClient
|
||||
RTITcp's are either client or server. The only difference is in
|
||||
their connect semantics. Servers normally block waiting for
|
||||
connections from clients.
|
||||
@param portNum
|
||||
value is any arbitrary desired. 0 to let the OS pick an ephemeral
|
||||
port. It is used by both ends to indicate the connection to be made.
|
||||
@param Action
|
||||
possible setsockopt action to perform before binding.
|
||||
|
||||
This returns a RTITcp object, which contains the rest of the
|
||||
functions that can manipulate its contents.
|
||||
|
||||
@return NULL if the TCP socket could not be created. Normally,
|
||||
this implies that the bind or listen call could not be done for a
|
||||
RTI_TCP_SERVER.
|
||||
*/
|
||||
RTITcp *RtiTcpNew(RTITcpConnectType serverOrClient,
|
||||
int portNum,
|
||||
RTITcpSetSockOptAction Action);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_tcp_h */
|
||||
@@ -0,0 +1,901 @@
|
||||
/* rti_time.h - built from: rtitime.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef rti_time_h
|
||||
#define rti_time_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "rtilib/rti_endian.h" /* For RTI_INT */
|
||||
#include "rtilib/rti_types.h" /* For RTIBool */
|
||||
|
||||
typedef RTI_UINT32 RTITimeUnit;
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
Represents infinite time value. Handy for specifying no timeout or
|
||||
sleeping forever.
|
||||
|
||||
@see RtiThreadSleep
|
||||
*/
|
||||
#define RTI_NTP_TIME_INFINITE ((RTINtpTime *)NULL)
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Zero time.
|
||||
|
||||
This global variable is for convenience. This allows users to
|
||||
check and see if a RTITime variable is negative or positive by comparing
|
||||
againt this.
|
||||
|
||||
@see RtiTimeCompare
|
||||
*/
|
||||
#define RTI_NTP_TIME_ZERO {0,0}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
Represents maximum timevalue that can be represented using the
|
||||
NTP time format. For all practical purposes, can be considered
|
||||
equivalent to infinity.
|
||||
|
||||
*/
|
||||
#define RTI_NTP_TIME_MAX {RTI_NTP_TIME_SEC_MAX,RTI_NTP_TIME_FRAC_MAX}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
The number of nanoseconds per second. 1e9.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_NSEC_PER_SEC ((RTITimeUnit)1000000000)
|
||||
/*e \ingroup rtiTime
|
||||
The number of microseconds per second. 1e6.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_USEC_PER_SEC ((RTITimeUnit)1000000)
|
||||
/*e \ingroup rtiTime
|
||||
The number of milliseconds per second. 1e3.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_MSEC_PER_SEC ((RTITimeUnit)1000)
|
||||
/*e \ingroup rtiTime
|
||||
The number of microseconds per milliseconds. 1e3.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_NSEC_PER_USEC ((RTITimeUnit)1000)
|
||||
/*e \ingroup rtiTime
|
||||
The number of microseconds per milliseconds. 1e3.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_USEC_PER_MSEC ((RTITimeUnit)1000)
|
||||
/*e \ingroup rtiTime
|
||||
The number of microseconds per milliseconds. 1e3.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_MSEC_PER_SEC ((RTITimeUnit)1000)
|
||||
/*e \ingroup rtiTime
|
||||
The number of seconds per second. 1.
|
||||
@see RtiTimePack RtiTimeUnpack
|
||||
*/
|
||||
#define RTI_TIME_SEC_PER_SEC ((RTITimeUnit)1)
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief NTP Time representation.
|
||||
|
||||
Expresses time in NTP format. The second field is simply an integer
|
||||
expressing seconds. The fraction field expresses 1/2^32 of a second.
|
||||
We strongly urge customers to use our provided macros to convert this
|
||||
format to and from human readable form.
|
||||
|
||||
RtiNtpTimeInit must be called before RtiNtpTimeGet. Creating a domain
|
||||
has the side-effect of calling RtiNtpTimeInit.
|
||||
|
||||
\b Example:
|
||||
|
||||
The following is a simple example on how to prepare a RTINtpTime structure
|
||||
to be 1.5 seconds.
|
||||
|
||||
\verbatim
|
||||
RTINtpTime ntpTime;
|
||||
|
||||
RtiNtpTimePackFromMillisec(ntpTime, 1, 500);
|
||||
\endverbatim
|
||||
|
||||
@see RtiNtpTimePackFromMillisec RtiNtpTimePackFromMicrosec
|
||||
@see RtiNtpTimePackFromNanosec
|
||||
@see RtiNtpTimeUnpackFromMillisec RtiNtpTimeUnpackFromMicrosec
|
||||
@see RtiNtpTimeUnpackFromNanosec
|
||||
*/
|
||||
typedef struct RTINtpTime {
|
||||
/*e Seconds.**/
|
||||
RTI_INT32 sec;
|
||||
/*e fraction of a second in 1/2^32 form.*/
|
||||
RTI_UINT32 frac;
|
||||
} RTINtpTime;
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
The maximum number of seconds that can be represented using NTP time.
|
||||
*/
|
||||
#define RTI_NTP_TIME_SEC_MAX ((RTI_INT32)0x7fffffff)
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
The largest possible value of the fraction field in NTP time.
|
||||
*/
|
||||
#define RTI_NTP_TIME_FRAC_MAX ((RTI_UINT32)0xffffffff)
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
@brief Set RTINtpTime time to zero.
|
||||
|
||||
@param time (RTINtpTime*) Pointer to RTINtpTime struct that needs to be
|
||||
set to zero.
|
||||
*/
|
||||
#define RTINtpTime_setZero(time) \
|
||||
{ \
|
||||
(time)->sec = 0; \
|
||||
(time)->frac = 0; \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
@brief Set RTINtpTime time to maximum value.
|
||||
|
||||
@param time (RTINtpTime*) Pointer to RTINtpTime struct that needs to be
|
||||
set to its maximum possible value.
|
||||
|
||||
The maximum possible value equals:
|
||||
|
||||
(time).sec = RTI_NTP_TIME_SEC_MAX
|
||||
(time).frac = RTI_NTP_TIME_FRAC_MAX
|
||||
|
||||
*/
|
||||
#define RTINtpTime_setMax(time) \
|
||||
{ \
|
||||
(time)->sec = RTI_NTP_TIME_SEC_MAX; \
|
||||
(time)->frac = RTI_NTP_TIME_FRAC_MAX; \
|
||||
}
|
||||
|
||||
#define RTINtpTime_toDouble(t) \
|
||||
(((double)((t)->frac)/4294967296.0f) + (double)(t)->sec)
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert from sec and milli-seconds to RTINtpTime format.
|
||||
|
||||
@param time (RTINtpTime) contains the answer.
|
||||
@param s (integer) Second to convert.
|
||||
@param msec (millisecond) fraction portion (less than 1000).
|
||||
|
||||
\verbatim
|
||||
RTINtpTime time;
|
||||
long sec, msec;
|
||||
sec = 10;
|
||||
msec = 577;
|
||||
|
||||
RtiNtpTimePackFromMillisec(time, sec, msec);
|
||||
\endverbatim
|
||||
|
||||
After the above call is made, the variable time will contain the equivalent
|
||||
time stamp in RTINtpTime representation.
|
||||
|
||||
This macro assumes that msec<1000. It is the callers responsibility
|
||||
to ensure this. This is done for performance reasons, the extra check slows
|
||||
the execution a factor of 5! If msec may be greater than 1000, you can invoke
|
||||
the macro as follows:
|
||||
\verbatim
|
||||
RtiNtpTimePackFromMillisec(time, sec + msec/1000, msec%1000);
|
||||
\endverbatim
|
||||
|
||||
This macro only evaluates its arguments once, so it is safe to invoke it
|
||||
with an argument that has side effects, that is. if you write:
|
||||
\verbatim
|
||||
RTI_UINT32 count = 10;
|
||||
RtiNtpTimePackFromMillisec(time, sec, count++)
|
||||
\endverbatim
|
||||
After the macro count is guaranteed to be 11.
|
||||
|
||||
The accuracy of this conversion over the whole range of millisecond values
|
||||
is 0.013 milli-seconds.
|
||||
|
||||
This is a fairly efficient macro. On a 400MHz Pentium-II linux box
|
||||
the execute time is about 0.06 usec.
|
||||
|
||||
\verbatim
|
||||
2^22*time.frac = ms + ms/2^6 + ms/2^7 + ms/2^11 + ms/2^14 + 1.3e-5
|
||||
= ms + ms*393/2^14;
|
||||
time.frac = (ms<<22) + (ms<<16) + (ms<<15) + (ms<<11) + (ms<<8)
|
||||
= (ms<<22) + ((ms*393)<<8)
|
||||
\endverbatim
|
||||
|
||||
@see RTINtpTime RtiNtpTimeUnpackToMillisec
|
||||
*/
|
||||
#define RtiNtpTimePackFromMillisec(time, s, msec) \
|
||||
{ \
|
||||
register RTI_UINT32 ms = msec; \
|
||||
(time).sec = s; \
|
||||
(time).frac = (ms<<22) + ((ms*393)<<8); \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert from RTINtpTime to sec and milli-seconds.
|
||||
|
||||
@param s (integer) Holds the seconds answer.
|
||||
@param msec (integer) Holds the millisecond answer.
|
||||
@param time (RTINtpTime) The time to convert to seconds and milliseconds.
|
||||
|
||||
This macro does not check for overflow, so for a near infinite time value,
|
||||
the conversion result may end up being negative. It is the responsibility
|
||||
of the user to avoid passing these large time values.
|
||||
|
||||
Use as indicated by the following code:
|
||||
\verbatim}
|
||||
RTINtpTime time;
|
||||
long sec, msec;
|
||||
|
||||
time.sec = 10;
|
||||
time.frac = 577;
|
||||
|
||||
RtiNtpTimeUnpackToMillisec(sec, msec, time);
|
||||
\endverbatim
|
||||
|
||||
After the above call is made, the variables "sec" and "msec" will
|
||||
contain the equivalent time stamp.
|
||||
|
||||
The accuracy of this conversion over the whole range of RTINtpTime values
|
||||
is 0.5 milli-seconds, except ntp value above {0x7fffffff, 0x7fffffff},
|
||||
accuracy is up to nearly 1 milli-seconds.
|
||||
|
||||
This is a fairly efficient macro. On a 400MHz Pentium-II linux box
|
||||
the execute time is about 0.08 usec
|
||||
|
||||
\verbatim
|
||||
ms/2^22 = frac*1000/1024 = frac*(1 - 24/1024) = frac*(1 - 3/2^7) =
|
||||
frac*(1 - 1/2^6 - 1/2^7)
|
||||
\endverbatim
|
||||
|
||||
@see RTINtpTime RtiNtpTimePackFromMillisec
|
||||
*/
|
||||
#define RtiNtpTimeUnpackToMillisec(s, msec, time) \
|
||||
{ \
|
||||
s = (time).sec; \
|
||||
msec = ((time).frac - ((time).frac>>6) - ((time).frac>>7) + (1<<21))>>22; \
|
||||
if( ((msec)>=1000)&&((s)!=0x7FFFFFFF) ) { (msec) -= 1000; (s)++; } \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert from sec and micro-seconds to RTINtpTime format.
|
||||
|
||||
@param time (RTINtpTime) to contain the answer.
|
||||
@param s (integer) second of the time to covert.
|
||||
@param usec (integer) microsecond fraction to convert from.
|
||||
|
||||
This macro does not check for overflow, so for a near infinite time value,
|
||||
the conversion result may end up being negative. It is the responsibility
|
||||
of the user to avoid passing these large time values.
|
||||
|
||||
Use as indicated by the following code:
|
||||
\verbatim
|
||||
RTINtpTime ntp;
|
||||
long sec, usec;
|
||||
sec = 10;
|
||||
usec = 577;
|
||||
|
||||
RtiNtpTimePackFromMicrosec(ntp, sec, usec);
|
||||
\endverbatim
|
||||
|
||||
After the above call is made, the variable ntp will contain the equivalent
|
||||
time stamp in RTINtpTime representation.
|
||||
|
||||
This macro assumes that msec<1000000. It is the callers responsibility
|
||||
to ensure this. This is done for performance reasons, the extra check
|
||||
slows the execution a factor of 5! If msec may be greater than 1000000,
|
||||
you can invoke the macro as follows:
|
||||
\verbatim
|
||||
RtiNtpTimePackFromMicrosec(ntp, sec + usec/1000000, usec%1000000);
|
||||
\endverbatim
|
||||
|
||||
This macro only evaluates its arguments once, so it is safe to invoke it
|
||||
with an argument that has side effects, that is. if you write:
|
||||
\verbatim
|
||||
RTI_UINT32 count = 10;
|
||||
RtiNtpTimePackFromMicrosec(ntp, sec, count++)
|
||||
\endverbatim
|
||||
|
||||
After the macro count is guaranteed to be 11.
|
||||
|
||||
The accuracy of this conversion over the whole range of microsecond values
|
||||
is 0.0028 micro-seconds.
|
||||
|
||||
This is a fairly efficient macro. On a 400MHz Pentium-II linux box
|
||||
the execute time is about 0.08 usec
|
||||
|
||||
\verbatim
|
||||
2^12 * ntp.frac = us + us/2^5 + us/2^6 + us/2^10 + us/2^11
|
||||
+ us/2^13 + us/2^14 + us/2^15 + us/2^16
|
||||
+ us/2^18 + us/2^19 + us/2^20 + us/2^21
|
||||
+ us/2^23 + 3e-9
|
||||
= us + us*99/2^11 + us*15/2^16 + us*61/2^23
|
||||
ntp.frac = (us<<12) + (us<<7) + (us<<6) + (us<<2) + (us<<1)
|
||||
+ (us>>1) + (us>>2) + (us>>3) + (us>>4)
|
||||
+ (us>>6) + (us>>7) + (us>>8) + (us>>9) + (us>>11)
|
||||
= (us<<12) + ((us*99)<<1)+ ((us*15)>>4)+ ((us*61)>>11)
|
||||
\endverbatim
|
||||
*/
|
||||
#define RtiNtpTimePackFromMicrosec(time, s, usec) \
|
||||
{ \
|
||||
register RTI_UINT32 us = usec; \
|
||||
(time).sec = s; \
|
||||
(time).frac = (us<<12)+ ((us*99)<<1)+ ((us*15 + ((us*61)>>7))>>4); \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert from RTINtpTime to sec and micro-seconds.
|
||||
|
||||
@param s (integer) Holds the second portion.
|
||||
@param usec (integer) holds the microsecond fraction.
|
||||
@param time (RTINtpTime) to be converted.
|
||||
|
||||
This macro does not check for overflow, so for a near infinite time value,
|
||||
the conversion result may end up being negative. It is the responsibility
|
||||
of the user to avoid passing these large time values.
|
||||
|
||||
Use as indicated by the following code:
|
||||
\verbatim
|
||||
RTINtpTime ntp;
|
||||
long sec, usec;
|
||||
|
||||
ntp.sec = 10;
|
||||
ntp.frac = 577;
|
||||
|
||||
RtiNtpTimeUnpackToMicrosec(sec, usec, ntp);
|
||||
\endverbatim
|
||||
|
||||
After the above call is made, the variables "sec" and "usec" will
|
||||
contain the equivalent time stamp.
|
||||
|
||||
The accuracy of this conversion over the whole range of RTINtpTime values
|
||||
is 0.5 micro-seconds, except ntp value above {0x7fffffff, 0x7fffffff},
|
||||
accuracy is up to nearly 1 milli-seconds.
|
||||
|
||||
This is a fairly efficient macro. On a 400MHz Pentium-II linux box
|
||||
the execute time is about 0.12 usec
|
||||
|
||||
\verbatim
|
||||
us = frac*1000000/2^20 = frac*( 1 - 48576/2^20 )
|
||||
= frac*(1 - 47/2^10 - 7/2^14)
|
||||
= frac - ((47*frac)>>10) - ((7*frac)>>14)
|
||||
= frac - (frac>>5)-(frac>>7)-(frac>>8)-(frac>>9)-(frac>>10)
|
||||
- (frac>>12)-(frac>>13)-(frac>>14)
|
||||
\endverbatim
|
||||
*/
|
||||
#define RtiNtpTimeUnpackToMicrosec(s, usec, time) \
|
||||
{ \
|
||||
register RTI_UINT32 rtiNtpTemp = (time).frac; \
|
||||
s = (time).sec; \
|
||||
usec = ((time).frac - (rtiNtpTemp>>5)-(rtiNtpTemp>>7)-(rtiNtpTemp>>8)- \
|
||||
(rtiNtpTemp>>9)-(rtiNtpTemp>>10) - (rtiNtpTemp>>12) - \
|
||||
(rtiNtpTemp>>13)-(rtiNtpTemp>>14) + (1<<11)) >> 12; \
|
||||
if( ((usec) >= 1000000) && ((s)!=0x7FFFFFFF) ) { \
|
||||
(usec) -= 1000000; \
|
||||
(s)++; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert from sec and nano-seconds to RTINtpTime format.
|
||||
|
||||
@param time (RTINtpTime) Holds the answer.
|
||||
@param s (integer) Seconds to convert from.
|
||||
@param nsec (integer) nanosecond fraction to convert from.
|
||||
|
||||
Use as indicated by the following code:
|
||||
\verbatim
|
||||
RTINtpTime time;
|
||||
long sec, nsec;
|
||||
sec = 10;
|
||||
nsec = 577;
|
||||
|
||||
RtiNtpTimePackFromNanosec(time, sec, msec);
|
||||
\endverbatim
|
||||
|
||||
After the above call is made, the variable time will contain the equivalent
|
||||
time stamp in RTINtpTime representation.
|
||||
|
||||
This macro assumes that nsec<1000000000. It is the callers responsibility
|
||||
to ensure this. This is done for performance reasons, the extra check
|
||||
slows the execution a factor of 5! If msec may be greater than 1000000, you
|
||||
can invoke the macro as follows:
|
||||
\verbatim}
|
||||
RtiNtpTimePackFromNanosec(time, sec + nsec/1000000000, nsec%1000000000);
|
||||
\endverbatim
|
||||
|
||||
This macro only evaluates its arguments once, so it is safe to invoke it
|
||||
with an argument that has side effects, that is. if you write:
|
||||
\verbatim
|
||||
RTI_UINT32 count = 10;
|
||||
RtiNtpTimePackFromNanosec(time, sec, count++)
|
||||
\endverbatim
|
||||
After the macro count is guaranteed to be 11.
|
||||
|
||||
The accuracy of this conversion over the whole range of nanosecond values
|
||||
is 0.5 nano-second, except ntp value above {0x7fffffff, 0x7fffffff},
|
||||
accuracy is up to nearly 1 milli-seconds.
|
||||
|
||||
This is a fairly efficient macro. On a 400MHz Pentium-II
|
||||
linux box the execute time is about 0.10 usec
|
||||
|
||||
\verbatim
|
||||
2^32/10^9 ns = 4*ns + ns/2^2 + ns/2^5 + ns/2^7 + ns/2^8 + ns/2^9 +
|
||||
ns/2^15 + ns/2^17 + ns/2^18 + ns/2^19 + ns/2^20 +
|
||||
ns/2^21 + ns/2^23 + ns/2^29 + ns/2^32
|
||||
|
||||
2^32/10^9 ns = 4*ns + (ns + ns/2^3 + ns/2^5 + ns/2^6 + ns/2^7 +
|
||||
ns/2^13 + ns/2^15 + ns/2^16 + ns/2^17 + ns/2^18 +
|
||||
ns/2^19 + ns/2^21 + ns/2^27 + ns/2^30)*(1/2^2)
|
||||
\endverbatim
|
||||
*/
|
||||
#define RtiNtpTimePackFromNanosec(time, s, nsec) \
|
||||
{ \
|
||||
register RTI_UINT32 ns = nsec; \
|
||||
(time).sec = s; \
|
||||
(time).frac = (ns<<2) + ((ns + (ns>>3) + (ns>>5) + (ns>>6) + \
|
||||
(ns>>7) + (ns>>13) + (ns>>15) + (ns>>16) + (ns>>17) + \
|
||||
(ns>>18) + (ns>>19) + (ns>>21) + (ns>>27) + (ns>>30))>>2); \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert from RTINtpTime to sec and nano-seconds.
|
||||
|
||||
@param s (integer) Second of the time to covert
|
||||
@param usec (integer) Microsecond fraction to convert.
|
||||
@param time (RTINtpTime) to convert from.
|
||||
|
||||
Use as indicated by the following code:
|
||||
\verbatim
|
||||
RTINtpTime time;
|
||||
long sec, nsec;
|
||||
time.sec = 10;
|
||||
time.frac = 577;
|
||||
|
||||
RtiNtpTimeUnpackToNanosec(sec, nsec, time);
|
||||
\endverbatim
|
||||
After the above call is made, the variables "sec" and "nsec" will
|
||||
contain the equivalent time stamp.
|
||||
|
||||
The accuracy of this conversion over the whole range of RTINtpTime values
|
||||
is 0.5 nsec This is a fairly efficient macro. On a 400MHz Pentium-II linux
|
||||
box the execute time is about 0.09 usec
|
||||
|
||||
Given that 294967296 = 0x1194d800 and
|
||||
\verbatim
|
||||
4*ns = frac*4000000000/2^32 = frac*(1 - 294967296/2^32)
|
||||
= frac*(1 - 1/2^4 - 1/2^8 - 9/2^12 - 4/2^16 - 13/2^20 - 8/2^24)
|
||||
= frac*(1 - 1>>4 - 1>>8 - 1>>9 - 1>>12 - 1>>14 - 1>>17 - 1>>18 -
|
||||
1>>20 - 1>>21)
|
||||
\endverbatim
|
||||
*/
|
||||
#define RtiNtpTimeUnpackToNanosec(s, nsec, time) \
|
||||
{ \
|
||||
register RTI_UINT32 rtiNtpTemp = (time).frac>>1; \
|
||||
register RTI_UINT32 rtiNtpDelta; \
|
||||
s = (time).sec; \
|
||||
rtiNtpDelta = (rtiNtpTemp) + (rtiNtpTemp>>4) + (rtiNtpTemp>>5) + \
|
||||
(rtiNtpTemp>>8) + (rtiNtpTemp>>10) + (rtiNtpTemp>>13) + \
|
||||
(rtiNtpTemp>>14)+ (rtiNtpTemp>>16) + (rtiNtpTemp>>17); \
|
||||
nsec = ((time).frac - ((rtiNtpDelta+4)>>3) + 1) >> 2; \
|
||||
if( (nsec>=1000000000) && ((s)!=0x7FFFFFFF) ) { \
|
||||
nsec -= 1000000000; \
|
||||
(s)++; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Precision used in bit manipulation for RTINtpTime fraction
|
||||
conversions
|
||||
|
||||
The larger the precision, the more bits you pick up in the long
|
||||
division to get the fraction. If precision is too large so that the
|
||||
denominator shifted by the precision bits blows the 2^32 limit, the
|
||||
result will be incorrect. For example, if denominator is 60 (a la
|
||||
Vx sysClkRate), precision_bits larger than 27 blows the limit and
|
||||
you get incorrect result. In general, the
|
||||
maximum precision_bits = 32 - (int)log2(denominator_per_sec),
|
||||
|
||||
where log2(x) can be calculated by:
|
||||
|
||||
\verbatim
|
||||
int log2answer = 0;
|
||||
while (x >>= 1) {1
|
||||
log2answer++;
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
For 60 (sysClkRateGet()), this would be 27.
|
||||
For gettimeofday() with microsec resolution, this would be 12.
|
||||
|
||||
But in practice, that kind of precision is not necessary nor desirable
|
||||
since the conversion would be slower. Instead, the precision is
|
||||
only important relative to the denominator. If your clock frequency
|
||||
is low (eg 60 Hz), you only have 16.6 ms resolution anyway. If you are
|
||||
within a tenth of your clock resolution that is probably good enough.
|
||||
|
||||
If we generalized too much and tried to handle nanosec resolution "ticks"
|
||||
we couldn't guarantee adequate acuracy for all ranges. So intenally, we
|
||||
just pick a reasonable number that gives us adequate accuracy over large
|
||||
ranges. I wanted a precision that will work well up to 1e6 tick rate
|
||||
(thinking about UNIX gettimeofday()), and 7 passed the test.
|
||||
|
||||
|
||||
*/
|
||||
#define RTI_NTP_TIME_PRECISION_BITS_DEFAULT 7
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Macro to convert numerator/denom_per_sec into the ntp time.
|
||||
|
||||
@param time RTINtpTime to contain the result. The existing
|
||||
content of time does not affect the result, as it should not.
|
||||
|
||||
@param numerator May be larger than denominator. Since this is a macro
|
||||
and numerator is evaluated multiple times, you shouldn't specify things
|
||||
like (i++).
|
||||
|
||||
@param denominator_per_sec Denominator.
|
||||
Physically, this means ticks per sec. Since this is a macro and
|
||||
denominator is evaluated multiple times, you shouldn't specify things
|
||||
like (i++).
|
||||
*/
|
||||
#define RtiNtpTimePackFromFraction(time, numerator, denominator_per_sec) \
|
||||
RTINtpTime_packFromFraction((time), (numerator), (denominator_per_sec), \
|
||||
RTI_NTP_TIME_PRECISION_BITS_DEFAULT)
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Transforms from RTINtpTime to any integral fraction of second without
|
||||
using floating point operations.
|
||||
|
||||
@param numerator RTI_UINT32 where to put the result of the conversion.
|
||||
|
||||
@param denominator_per_sec the number of units of the fraction contained in
|
||||
a second. Should be 1000 to convert to millisec, or 60 if using default
|
||||
Vx clock rate, or whatever.
|
||||
|
||||
@param time RTINtpTime to unpack
|
||||
|
||||
The algoritm is based on the observation that the time.frac looked
|
||||
as a sequence of bits: b[1], b[2], b[3], ... represents the
|
||||
following expansion
|
||||
|
||||
time_in_sec = b[1]*1/2 + b[1]*1/4 +...+ b[2]*1/8
|
||||
= Sum{i=1..32} b[i]*1/2^i
|
||||
|
||||
So given that what we want to obtain is the time in units of which
|
||||
there are denominator_per_sec units in a second, the arithmetic is:
|
||||
|
||||
time_in_units = denominator_per_sec*time_in_sec
|
||||
= denominator_per_sec*time.sec+denominator_per_sec*time.frac
|
||||
|
||||
And denominator_per_sec*time.frac =
|
||||
Sum{i=1..32} b[i]*(denominator_per_sec/2^i)
|
||||
the key here is that b[i] is easily computed as (1<<31)>>(i-1)
|
||||
and (denominator_per_sec/2^i) is easily computed as denominator_per_sec>>i
|
||||
|
||||
Note that each time we compute (denominator_per_sec/2^i) to add it we may
|
||||
be off by one unit. Therefore at the end of the computation we may
|
||||
be off by log2(denominator_per_sec) units which means we should in fact
|
||||
perform each step with an accuracy of log2(2*denominator_per_sec)
|
||||
greater. In other words, we should use units a factor
|
||||
log2(2*denominator_per_sec) greater than the ones we require at the end
|
||||
of the conversion.
|
||||
|
||||
The other key observation is that the computation can end as soon
|
||||
as (denominator_per_sec<<RTI_NTP_TIME_PRECISION_BITS_DEFAULT)>>i becomes
|
||||
zero because thet means that what is left has a significance of
|
||||
less than one unit>>RTI_NTP_TIME_PRECISION_BITS_DEFAULT. This will give a
|
||||
conversion that is strictly
|
||||
smaller than the NTP timestamp. For example, for millisecond
|
||||
conversion log2(1000) = 10 so we will do 10 operations so we need a
|
||||
precision 1/20 or 5 bits (4 bits gives 1/16, 5 gives 1/32).
|
||||
|
||||
The final operation:
|
||||
(precision_units + (1<<RTI_NTP_TIME_PRECISION_BITS_DEFAULT-1))>>
|
||||
RTI_NTP_TIME_PRECISION_BITS_DEFAULT;
|
||||
makes sure that the integer division by
|
||||
2^(RTI_NTP_TIME_PRECISION_BITS_DEFAULT) is
|
||||
rounded off to the closest number.
|
||||
*/
|
||||
#define RtiNtpTimeUnpackToFraction(numerator, denominator_per_sec, time) \
|
||||
RTINtpTime_unpackToFraction((numerator), (denominator_per_sec), (time), \
|
||||
RTI_NTP_TIME_PRECISION_BITS_DEFAULT)
|
||||
|
||||
#define RTINtpTime_packFromFraction(time, numerator, denominator_per_sec, \
|
||||
precisionBits) \
|
||||
{ \
|
||||
register RTI_UINT32 current_bit = 0x80000000; \
|
||||
register RTI_UINT32 current_units = (denominator_per_sec)<<precisionBits; \
|
||||
register RTI_UINT32 precision_numerator = \
|
||||
((numerator)%(denominator_per_sec))<< precisionBits; \
|
||||
(time).sec = (numerator)/(denominator_per_sec); \
|
||||
(time).frac = 0; \
|
||||
while (current_units >>= 1) { \
|
||||
(time).frac += \
|
||||
(((precision_numerator) >= current_units) ? \
|
||||
(((precision_numerator) -= current_units), current_bit) : 0); \
|
||||
current_bit >>= 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RTINtpTime_unpackToFraction(numerator, denominator_per_sec, time, \
|
||||
precisionBits) \
|
||||
{ \
|
||||
register RTI_UINT32 current_bit = 0x80000000; \
|
||||
register RTI_UINT32 current_units = (denominator_per_sec)<<(precisionBits);\
|
||||
register RTI_UINT32 precision_numerator = 0; \
|
||||
numerator = (denominator_per_sec)*(time).sec; \
|
||||
while ((current_units >>= 1)) { \
|
||||
precision_numerator += ((time).frac & current_bit) ? current_units:0;\
|
||||
current_bit >>= 1; \
|
||||
} \
|
||||
numerator += (precision_numerator + \
|
||||
(1<<((precisionBits)-1)))>>(precisionBits);\
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Compare two RTINtpTimes.
|
||||
|
||||
@param time1 RTINtpTime, NOT NULL.
|
||||
@param time2 RTINtpTime, NOT NULL.
|
||||
|
||||
@return If time1 > time2 then return 1. If time1 < time2 then return -1.
|
||||
If time1 == time2 then return 0.
|
||||
*/
|
||||
#define RtiNtpTimeCompare(time1, time2) \
|
||||
((((time1).sec) > ((time2).sec)) ? 1 : \
|
||||
((((time1).sec) < ((time2).sec)) ? -1 : \
|
||||
((((time1).frac) > ((time2).frac)) ? 1 : \
|
||||
((((time1).frac) < ((time2).frac)) ? -1 : 0))))
|
||||
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief answer = t1 + t2.
|
||||
|
||||
This macro does not check for overflow (faster).
|
||||
|
||||
@param answer RTINtpTime
|
||||
@param t1 RTINtpTime
|
||||
@param t2 RTINtpTime
|
||||
*/
|
||||
#define RtiNtpTimeAdd(answer, t1, t2) \
|
||||
{\
|
||||
(answer).sec = (t1).sec + (t2).sec; \
|
||||
(answer).frac = (t1).frac + (t2).frac; \
|
||||
if (((answer).frac < (t1).frac) || ((answer).frac < (t2).frac)) { \
|
||||
(answer).sec++; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief answer = t1 - t2.
|
||||
|
||||
@param answer RTINtpTime
|
||||
@param t1 RTINtpTime
|
||||
@param t2 RTINtpTime
|
||||
*/
|
||||
#define RtiNtpTimeSubtract(answer, t1, t2) \
|
||||
{\
|
||||
(answer).sec = (t1).sec - (t2).sec; \
|
||||
(answer).frac = (t1).frac - (t2).frac; \
|
||||
if ((answer).frac > (t1).frac) { \
|
||||
(answer).sec--; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief answer = time << shift.
|
||||
|
||||
To use this macro for multiplying by a num, shift can be calculated
|
||||
as log10(num)/log10(2).
|
||||
|
||||
@param answer RTINtpTime
|
||||
@param time RTINtpTime
|
||||
@param shift int
|
||||
*/
|
||||
#define RtiNtpTimeLeftShift(answer, time, shift) \
|
||||
{\
|
||||
register RTI_UINT32 mask = 0xffffffff; \
|
||||
if (shift) { \
|
||||
(answer).sec = ((time).sec)<<shift; \
|
||||
mask = mask<<(32 - shift); \
|
||||
mask &= (time).frac; \
|
||||
mask = mask>>(32 - shift); \
|
||||
(answer).sec |= mask; \
|
||||
(answer).frac = ((time).frac)<<shift; \
|
||||
} \
|
||||
else { \
|
||||
answer = time; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief answer = time >> shift.
|
||||
|
||||
To use this macro for dividing by a num, shift can be calculated
|
||||
as log10(num)/log10(2).
|
||||
|
||||
@param answer RTINtpTime
|
||||
@param time RTINtpTime
|
||||
@param shift int
|
||||
*/
|
||||
#define RtiNtpTimeRightShift(answer, time, shift) \
|
||||
{\
|
||||
register RTI_UINT32 mask = 0xffffffff; \
|
||||
if (shift) { \
|
||||
(answer).frac = ((time).frac)>>shift; \
|
||||
mask = mask>>(32 - shift); \
|
||||
mask &= (time).sec; \
|
||||
mask = mask<<(32 - shift); \
|
||||
(answer).frac |= mask; \
|
||||
(answer).sec = ((time).sec)>>shift; \
|
||||
} \
|
||||
else { \
|
||||
answer = time; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup
|
||||
|
||||
@brief answer += time.
|
||||
|
||||
This macro does not check for overflow.
|
||||
|
||||
@param answer RTINtpTime
|
||||
@param time RTINtpTime
|
||||
*/
|
||||
#define RtiNtpTimeIncrement(answer, time) \
|
||||
{ \
|
||||
register RTI_UINT32 currentFrac = (answer).frac; \
|
||||
(answer).sec += (time).sec; \
|
||||
(answer).frac += (time).frac; \
|
||||
if (((answer).frac < (time).frac) || ((answer).frac < currentFrac)) { \
|
||||
(answer).sec++; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Decrement one RTINtpTime value by another RTINtpTime value.
|
||||
|
||||
Precondition:
|
||||
Postcondition: answer -= time.
|
||||
|
||||
@param answer RTINtpTime
|
||||
@param time RTINtpTime
|
||||
|
||||
*/
|
||||
#define RtiNtpTimeDecrement(answer, time) \
|
||||
{ \
|
||||
register RTI_UINT32 currentFrac = (answer).frac; \
|
||||
(answer).sec -= (time).sec; \
|
||||
(answer).frac -= (time).frac; \
|
||||
if (((answer).frac > currentFrac)) { (answer).sec--; } \
|
||||
}
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief time = time + 1 fraction (~200 pico seconds).
|
||||
|
||||
This macro does not check for overflow, so time cannot be infinite.
|
||||
|
||||
@param time
|
||||
@return NO RETURN VALUE => do NOT evaluate this expression; simply call it.
|
||||
*/
|
||||
#define RtiNtpTimeIncrementInfinitesimally(time) \
|
||||
((++((time).frac)) == 0) ? ++(time).sec : 0
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief The length of the buffer necessary to call RtiNtpTimeToString.
|
||||
|
||||
@see RtiNtpTimeToString.
|
||||
*/
|
||||
#define RTI_NTP_TIME_STRING_LEN 22
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
NULL RTINtpTime pointer is considered infinity. This is consistent
|
||||
with the concept of infinite time on UNIX.
|
||||
|
||||
In addition, if the seconds field equals RTI_NTP_TIME_SEC_MAX, the
|
||||
time value is also considered infinite.
|
||||
|
||||
@param time Pointer to RTITime.
|
||||
@return RTI_TRUE if time is infinite, RTI_FALSE otherwise.
|
||||
|
||||
*/
|
||||
#define RtiNtpTimeIsInfinite(time) ((!(time) || \
|
||||
((time)->sec == RTI_NTP_TIME_SEC_MAX))? \
|
||||
RTI_TRUE : RTI_FALSE)
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
Checks if the time structure represents zero time. Zero time may be useful
|
||||
when getting the sign of the time quantity.
|
||||
@param time Pointer to RTINtpTime. Must not be NULL.
|
||||
@return RTI_TRUE if time is zero, RTI_FALSE otherwise.
|
||||
*/
|
||||
#define RtiNtpTimeIsZero(time) (((time) && (time)->sec==0 && \
|
||||
(time)->frac==0) ? \
|
||||
RTI_TRUE : RTI_FALSE)
|
||||
|
||||
extern DllExport
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Converts a RTINtpTime to a string.
|
||||
|
||||
The maximum string length we need is RTI_NTP_TIME_STRING_LEN.
|
||||
|
||||
@param str The string to hold the result.
|
||||
@param time The value to convert.
|
||||
|
||||
@return string representation of RTINtpTime for the desired resolution.
|
||||
NULL if str NULL or invalid resolution.
|
||||
*/
|
||||
char *RtiNtpTimeToString(const RTINtpTime *time, char *str);
|
||||
|
||||
extern DllExport
|
||||
char *RTINtpTime_toString(const RTINtpTime *time, char *str);
|
||||
|
||||
extern DllExport
|
||||
/*
|
||||
Depending on the OS and the clock mode, this may not be the true
|
||||
clock frequency, but the frequency of the values returned by the OS.
|
||||
*/
|
||||
int RtiNtpTimeFrequencyGet(void);
|
||||
|
||||
extern DllExport
|
||||
RTIBool RtiNtpTimeResolutionGet(RTINtpTime *resolution);
|
||||
|
||||
extern DllExport
|
||||
/* Epoch is the amount of time the OS clock will jump in the wrap around
|
||||
event, and therefore the amount of time we have to compensate for, AS LONG
|
||||
AS the clock tick returned by the OS (if the OS uses clock tick to return
|
||||
time) is *unsigned*.
|
||||
*/
|
||||
RTIBool RtiNtpTimeEpochRangeGet(RTINtpTime *range);
|
||||
|
||||
extern DllExport
|
||||
RTIBool RtiNtpTimeInit(RTINtpTime *resolution, RTINtpTime *epochRange);
|
||||
|
||||
|
||||
/*e \ingroup rtiTime
|
||||
|
||||
@brief Return a OS time.
|
||||
|
||||
Callers must provide the additional functionality of providing
|
||||
struct monotonicity and compensate for wrap.
|
||||
|
||||
@see RtiNtpTimeInit
|
||||
*/
|
||||
extern DllExport RTIBool RtiNtpTimeGet(RTINtpTime *now);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* rti_time_h */
|
||||
@@ -0,0 +1,122 @@
|
||||
/* rti_type.h - Variable type macro define */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
40c,05apr00,sst Included types.h for pSOS as this defines NULL
|
||||
39a,15oct98,hhw Removed bool. Now we only have RTIBool.
|
||||
38c,27aug98,nm Do not define RTI_WIN32 on Windows CE, rather define RTI_WINCE!
|
||||
38b,13Jul98,mlh Removed boolean. Now we only have bool.
|
||||
37k,15may98,nm Define RTI_WIN32 if _WIN32 is defined.
|
||||
38a,08may98,nm Use _MSC_VER.
|
||||
37i,19Mar98,mlh Added DllExport for windows.
|
||||
37i,03mar98,nm Nope, for VC++, bool needs to be defined for 4.0 (C or C++),
|
||||
and for 5.0C, but not for 5.0C++.
|
||||
37i,03nov97,mlh Must define bool for VC4.0 when compiling anything.
|
||||
37h,03nov97,nm Must define bool for VC++5.0 when compiling C files. Added
|
||||
RTI_WINCE ifdef.
|
||||
37h,29sep97,nm On Windows platform, no longer declare typedef for bool since
|
||||
VC++5.0 internally defines it. Added RTI_NTVC.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Variable type macro define
|
||||
*/
|
||||
|
||||
/* defines */
|
||||
|
||||
#ifndef rti_types_h
|
||||
#define rti_types_h
|
||||
|
||||
#if defined(_WIN32) && !defined(RTI_SIMNT)
|
||||
#if !defined(_WIN32_WCE)
|
||||
#ifndef RTI_WIN32
|
||||
#define RTI_WIN32
|
||||
#endif
|
||||
#else
|
||||
#ifndef RTI_WINCE
|
||||
#define RTI_WINCE
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(RTI_PSOS)
|
||||
#include <types.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL (0)
|
||||
#else
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
typedef unsigned int uint;
|
||||
#endif
|
||||
|
||||
#if defined(RTI_WIN32) || defined(RTI_NTVC) || defined(RTI_WINCE)
|
||||
/*
|
||||
Ramnivas: Added these pragma to stop complier issuing warning
|
||||
For MFC based code this is done in Yvals.h
|
||||
*/
|
||||
#pragma warning(disable:4237)
|
||||
#pragma warning(disable:4068)
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned int u_int;
|
||||
#endif /* RTI_WIN32 */
|
||||
|
||||
|
||||
typedef int RTIBool;
|
||||
#define RTI_FALSE ((RTIBool) 0)
|
||||
#define RTI_TRUE ((RTIBool) 1)
|
||||
|
||||
/*
|
||||
Using DLL declares:
|
||||
When rtilib is being compiled as a DLL, define both
|
||||
RTI_DLL_EXPORT and RTI_DLL_VARIABLE, this will cause
|
||||
the variables and functions to be exported in the DLL.
|
||||
|
||||
To link against the rtilib DLL, define RTI_DLL_VARIABLE
|
||||
if you access any of the exported *variables*. It is not
|
||||
needed if you do not access any of the global variables in
|
||||
the DLL.
|
||||
|
||||
Functions will be linked correctly by an application using
|
||||
the DLL without having to define either RTI_DLL_EXPORT
|
||||
or RTI_DLL_VARIABLE
|
||||
*/
|
||||
#if defined(RTI_WIN32) || defined(RTI_WINCE)
|
||||
#if defined(RTI_DLL_EXPORT)
|
||||
#define DllExport __declspec( dllexport )
|
||||
#else
|
||||
#define DllExport
|
||||
#endif /* RTI_RTILIBDLL */
|
||||
|
||||
#if defined(RTI_DLL_VARIABLE)
|
||||
#if defined(RTI_DLL_EXPORT)
|
||||
#define DllVariable __declspec( dllexport )
|
||||
#else
|
||||
#define DllVariable __declspec( dllimport )
|
||||
#endif /* RTI_DLL_EXPORT */
|
||||
#else
|
||||
#define DllVariable
|
||||
#endif /* RTI_DLL_VARIABLE */
|
||||
#else
|
||||
#define DllExport
|
||||
#define DllVariable
|
||||
#endif /* RTI_WIN32 || RTI_WINCE */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,485 @@
|
||||
/* stSpinLock.h - ScopeTools Spin Lock Library Header */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007-2010 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01c,16dec10,zlo Use new typed error values (WIND00246074)
|
||||
01b,11mar10,flu Modified the code for diab compilation (CQ:WIND00146073)
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
6.1 ,23sep08,mas _WRS_VX_SMP -> WRS_CONFIG_SMP + vsbConfig.h
|
||||
3.3b,22jul08,mas added rti_types.h for RTIBool declaration
|
||||
3.3a,10jul07,mas isolated VxWorks section from future Linux section; made
|
||||
VxWorks section available for all versions
|
||||
3.3a,10may07,mas created
|
||||
*/
|
||||
/* $Id: stSpinLock.h,v 1.11 2007/11/17 01:03:31 mstanek Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
This file contains the declaration header for the spin lock library.
|
||||
It contains support for locks of many types, not just spin locks.
|
||||
All the routines are declared to be inline functions.
|
||||
|
||||
There are two types of spin locks supported in this library, read/write (R/W)
|
||||
and preemption. The two must never be mixed! To help enforce this, two
|
||||
distinct types are typedefed in this file and must be used when calling
|
||||
the functions.
|
||||
|
||||
The R/W spin lock is used for mutual exclusion of multiple accesses to
|
||||
shared data of either read or write nature. A read locked resource may
|
||||
be locked by more than one reader and precludes any write operation that
|
||||
could change the data. A write locked resource can be written by only
|
||||
the one task holding the lock; no other task can read or write it. R/W
|
||||
operations are supported by these routines: taskRDlock(), taskRDunlock(),
|
||||
taskWRlock(), taskWRunlock().
|
||||
|
||||
Preemption locks are used to lock sections of code that access and/or
|
||||
alter shared resources. They are a light-weight form of mutex semaphore
|
||||
and are supported by these routines: task_lock() and task_unlock().
|
||||
|
||||
Note that these spin locks are not the same as VxWorks spin locks. VxWorks
|
||||
spin locks have severe restrictions imposed when they are used and are
|
||||
generally not practical for use within applications.
|
||||
|
||||
In addition to the spin locks there are macros defined for use with the
|
||||
spin locks and with OS-specific forms of interrupt and ISR locking.
|
||||
|
||||
There are specific types of locks to be used when using the macros:
|
||||
|
||||
st_rwLock - must be used with R/W locks and only R/W locks
|
||||
st_preemptLock - must be used with preemption locks and only preemption locks
|
||||
st_isrLock - must be used with ISR locks and only ISR locks
|
||||
|
||||
The interrupt lock type is 'int'.
|
||||
|
||||
USING LOCKS
|
||||
Spin locks should be declared as non-static globals preset to zero for
|
||||
most applications. Spin locks may also be preset to a non-zero value
|
||||
if the associated resources require protection during initialization.
|
||||
When the initialization routine finishes, it can then release the spin lock.
|
||||
|
||||
These spin locks are for use within multi-processor and multi-tasking
|
||||
applications and follow cooperative programming rules, that is, all parts of
|
||||
an application must follow the same usage rules with respect to sharing data
|
||||
and critical sections of code.
|
||||
|
||||
CAVEAT: These spin locks are designed to be very light weight and to be fast,
|
||||
so no ownership is recorded or checked nor are spurious/multiple takes or
|
||||
gives checked for.
|
||||
|
||||
R/W spin locks can have many values, following these rules:
|
||||
|
||||
- A value of 0 always means the lock is released.
|
||||
|
||||
- A value of WR_INC or greater means a single writer owns the lock.
|
||||
|
||||
- Values from 1 to some positive integer less than WRITER_INC indicate one
|
||||
or more tasks have locked a resource for reading only.
|
||||
|
||||
Preemption spin locks have only two values, 0 or 1. Zero (0) always means
|
||||
the lock is released and one (1) means a single task has locked a code
|
||||
section and the data it manipulates.
|
||||
|
||||
CAVEAT: Preemption and R/W locks must never be mixed! Chaos will ensue if
|
||||
they are!
|
||||
|
||||
All spin locks require initialization before use. The task_lock_init() and
|
||||
rw_lock_init() routines are provided for this.
|
||||
|
||||
When finished using spin locks, the locks should be reclaimed using these
|
||||
routines: task_lock_done() and rw_lock_done(). Failure to do so can produce
|
||||
memory leaks.
|
||||
|
||||
ISR locks require an OS-specific initialization before they can be used, so
|
||||
always use the ISR lock initialization macro isr_lock_init(), once per lock.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#ifndef stSpinLock_h
|
||||
#define stSpinLock_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef RTI_VXWORKS
|
||||
#include <rtilib/vxVersions.h>
|
||||
#include <rtilib/rti_types.h>
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#include <intLib.h>
|
||||
|
||||
#undef SMP_CONFIG
|
||||
#if VXWORKS_VERSION_6_7_OR_BETTER
|
||||
# include <vsbConfig.h>
|
||||
# ifdef _WRS_CONFIG_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#else
|
||||
# ifdef _WRS_VX_SMP
|
||||
# define SMP_CONFIG
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# if defined(SMP_CONFIG)
|
||||
# include <spinLockLib.h>
|
||||
# include <vxAtomicLib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <semLib.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
#define SPIN 0
|
||||
|
||||
/* Spin Lock Types */
|
||||
# if (SPIN)
|
||||
typedef atomic_t st_rwLock;
|
||||
typedef atomic_t st_preemptLock;
|
||||
# else
|
||||
typedef SEM_ID st_rwLock;
|
||||
typedef SEM_ID st_preemptLock;
|
||||
# endif
|
||||
typedef spinlockIsr_t st_isrLock;
|
||||
|
||||
/* Version-specific Prototypes */
|
||||
void isr_lock (st_isrLock *);
|
||||
|
||||
|
||||
/* Macros */
|
||||
# define task_lock(pLock) stPreemptLockTake(pLock)
|
||||
# define task_unlock(pLock) stPreemptLockGive(pLock)
|
||||
# define task_lock_init(pLock) stPreemptLockInit(pLock)
|
||||
# define task_lock_done(pLock) stPreemptLockDone(pLock)
|
||||
# define taskRDlock(pLock) stReadLockTake(pLock)
|
||||
# define taskRDunlock(pLock) stReadLockGive(pLock)
|
||||
# define taskWRlock(pLock) stWriteLockTake(pLock)
|
||||
# define taskWRunlock(pLock) stWriteLockGive(pLock)
|
||||
# define rw_lock_init(pLock) stRWlockInit(pLock)
|
||||
# define rw_lock_done(pLock) stRWlockDone(pLock)
|
||||
|
||||
# define int_lock(key) key=INT_CPU_LOCK()
|
||||
# define int_unlock(key) INT_CPU_UNLOCK(key)
|
||||
# define isr_lock(pLock) SPIN_LOCK_ISR_TAKE(pLock)
|
||||
# define isr_unlock(pLock) SPIN_LOCK_ISR_GIVE(pLock)
|
||||
# define isr_lock_init(pLock) SPIN_LOCK_ISR_INIT(pLock,0)
|
||||
|
||||
/* Writer Increment */
|
||||
# define WR_INC 0x1000
|
||||
|
||||
/* Version-agnostic Prototypes */
|
||||
#ifdef __DCC__ /* Hack: detect Diab compiler */
|
||||
static __inline__ void stWriteLockTake (st_rwLock*);
|
||||
static __inline__ void stWriteLockGive (st_rwLock*);
|
||||
static __inline__ void stReadLockTake (st_rwLock*);
|
||||
static __inline__ void stReadLockGive (st_rwLock*);
|
||||
static __inline__ void stPreemptLockTake (st_preemptLock*);
|
||||
static __inline__ void stPreemptLockGive (st_preemptLock*);
|
||||
static __inline__ RTIBool stPreemptLockInit (st_preemptLock*);
|
||||
static __inline__ RTIBool stRWlockInit (st_rwLock*);
|
||||
static __inline__ void stPreemptLockDone (st_preemptLock*);
|
||||
static __inline__ void stRWlockDone (st_rwLock*);
|
||||
# else
|
||||
static __inline__ void stWriteLockTake (st_rwLock*) __attribute__((always_inline));
|
||||
static __inline__ void stWriteLockGive (st_rwLock*) __attribute__((always_inline));
|
||||
static __inline__ void stReadLockTake (st_rwLock*) __attribute__((always_inline));
|
||||
static __inline__ void stReadLockGive (st_rwLock*) __attribute__((always_inline));
|
||||
static __inline__ void stPreemptLockTake (st_preemptLock*) __attribute__((always_inline));
|
||||
static __inline__ void stPreemptLockGive (st_preemptLock*) __attribute__((always_inline));
|
||||
static __inline__ RTIBool stPreemptLockInit (st_preemptLock*) __attribute__((always_inline));
|
||||
static __inline__ RTIBool stRWlockInit (st_rwLock*) __attribute__((always_inline));
|
||||
static __inline__ void stPreemptLockDone (st_preemptLock*) __attribute__((always_inline));
|
||||
static __inline__ void stRWlockDone (st_rwLock*) __attribute__((always_inline));
|
||||
# endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stPreemptLockInit - initialize preemption spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine initializes a preemption spin lock. It must be called before
|
||||
* using any preemption spin lock.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock initialized, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stPreemptLockGive(), stPreemptLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ RTIBool stPreemptLockInit (st_preemptLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
vxAtomicClear (pSl);
|
||||
return (RTI_TRUE);
|
||||
#else
|
||||
*pSl = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
|
||||
return ((*pSl == SEM_ID_NULL) ? RTI_FALSE : RTI_TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stPreemptLockDone - reclaim preemption spin lock resources
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine reclaims resources of a preemption spin lock. It should be
|
||||
* called whenever a tool has finished using any preemption spin lock.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock reclaimed, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stPreemptLockGive(), stPreemptLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stPreemptLockDone (st_preemptLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
vxAtomicClear (pSl);
|
||||
#else
|
||||
(void) semDelete (*pSl);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stRWlockInit - initialize task spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine initializes a Read/Write spin lock. It must be called before
|
||||
* using any RW spin lock.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock initialized, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stWriteLockGive(), stReadLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ RTIBool stRWlockInit (st_rwLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
vxAtomicClear (pSl);
|
||||
return (RTI_TRUE);
|
||||
#else
|
||||
*pSl = semRWCreate (SEM_Q_PRIORITY, 100);
|
||||
return ((*pSl == NULL) ? RTI_FALSE : RTI_TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stRWlockDone - reclaim RW spin lock resources
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine reclaims resources of a Read/Write spin lock. It should be
|
||||
* called whenever a tool has finished using any RW spin lock.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock reclaimed, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stWriteLockGive(), stReadLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stRWlockDone (st_preemptLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
vxAtomicClear (pSl);
|
||||
#else
|
||||
(void) semDelete (*pSl);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stWriteLockTake - take write spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine spins on taking a write lock while the CPU is locked. No read
|
||||
* operations nor any other write operation can proceed once this lock is
|
||||
* taken.
|
||||
*
|
||||
* CAVEAT: No error checking is done nor is verification done to see if
|
||||
* this call can be made.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock taken, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stWriteLockGive(), stReadLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stWriteLockTake (st_rwLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
#else
|
||||
(void) semWTake (*pSl, WAIT_FOREVER);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stWriteLockGive - give write spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine releases a write lock and unlocks the CPU.
|
||||
*
|
||||
* CAVEAT: No error checking is done nor is verification done to see if
|
||||
* the caller is the one which took the write lock!
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock given, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stWriteLockTake(), stReadLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stWriteLockGive (st_rwLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
#else
|
||||
(void) semGive (*pSl);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stReadLockTake - take read spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine spins on taking a read lock while the CPU is locked. Other
|
||||
* read operations may proceed but no write operation can proceed once this
|
||||
* lock is taken.
|
||||
*
|
||||
* CAVEAT: No error checking is done nor is verification done to see if
|
||||
* this call can be made.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock taken, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stReadLockGive(), stWriteLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stReadLockTake (st_rwLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
#else
|
||||
(void) semRTake (*pSl, WAIT_FOREVER);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stReadLockGive - give read spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine releases a read lock and unlocks the CPU.
|
||||
*
|
||||
* CAVEAT: No error checking is done nor is verification done to see if
|
||||
* this call can be made or if the caller is one which took a read lock.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock given, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stReadLockTake(), stWriteLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stReadLockGive (st_rwLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
#else
|
||||
(void) semGive (*pSl);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stPreemptLockTake - take preemption spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine spins on taking a preemption lock while the CPU is locked.
|
||||
* No other operations, read or write, can proceed once this lock is taken.
|
||||
*
|
||||
* CAVEAT: No error checking is done nor is verification done to see if
|
||||
* this call can be made.
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock taken, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stPreemptLockGive(), stReadLockTake(), stWriteLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stPreemptLockTake (st_preemptLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
taskCpuLock (); /* no blocking calls after this point! */
|
||||
while (!vxCas (pSl, 0, 1)) { }
|
||||
#else
|
||||
(void) semTake (*pSl, WAIT_FOREVER);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* stPreemptLockGive - give preemption spin lock
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine releases a preemption lock and unlocks the CPU.
|
||||
*
|
||||
* CAVEAT: No error checking is done nor is verification done to see if
|
||||
* the caller is the one which took the preemption lock!
|
||||
*
|
||||
* RETURNS: RTI_TRUE if lock given, else, RTI_FALSE
|
||||
*
|
||||
* SEE ALSO: stPreemptLockTake(), stReadLockTake(), stWriteLockTake()
|
||||
*/
|
||||
|
||||
static __inline__ void stPreemptLockGive (st_preemptLock * pSl)
|
||||
{
|
||||
#if (SPIN)
|
||||
vxAtomicClear (pSl);
|
||||
taskCpuUnlock ();
|
||||
#else
|
||||
(void) semGive (*pSl);
|
||||
#endif
|
||||
}
|
||||
|
||||
# else /* if defined(SMP_CONFIG) */
|
||||
|
||||
/* Spin Lock Types */
|
||||
typedef int st_rwLock;
|
||||
typedef int st_preemptLock;
|
||||
typedef int st_isrLock;
|
||||
|
||||
/* Macros */
|
||||
# define task_lock(pLock) (void)taskLock()
|
||||
# define task_unlock(pLock) (void)taskUnlock()
|
||||
# define taskRDlock(pLock) (void)taskLock()
|
||||
# define taskRDunlock(pLock) (void)taskUnlock()
|
||||
# define taskWRlock(pLock) (void)taskLock()
|
||||
# define taskWRunlock(pLock) (void)taskUnlock()
|
||||
# define task_lock_init(pLock) (RTI_TRUE)
|
||||
# define task_lock_done(pLock)
|
||||
# define rw_lock_init(pLock) (RTI_TRUE)
|
||||
# define rw_lock_done(pLock)
|
||||
# define int_lock(key) key=intLock()
|
||||
# define int_unlock(key) intUnlock(key)
|
||||
# define isr_lock(pLock) *pLock = intLock()
|
||||
# define isr_unlock(pLock) intUnlock(*pLock)
|
||||
# define isr_lock_init(pLock)
|
||||
|
||||
# endif /* if defined(SMP_CONFIG) */
|
||||
#endif /* RTI_VXWORKS */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* stSpinLock_h */
|
||||
@@ -0,0 +1,91 @@
|
||||
/* vxVersions.h - Define versioning macros */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2010 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
This file defines some macros that help smooth over the VxWorks version
|
||||
differences. It expects the compiler to define __VXWORKS__ and vxWorks.h
|
||||
to define _WRS_VXWORKS_[MAJOR,MINOR].
|
||||
*/
|
||||
|
||||
|
||||
#ifndef vxversions_h
|
||||
#define vxversions_h
|
||||
|
||||
#if defined(__VXWORKS__)
|
||||
# include <vxWorks.h>
|
||||
# include <version.h>
|
||||
#endif
|
||||
|
||||
#define VXWORKS_VERSION_5_0_OR_BETTER \
|
||||
(defined(RTI_VXWORKS) && _WRS_VXWORKS_MAJOR >= 5)
|
||||
|
||||
#define VXWORKS_VERSION_5_1_OR_BETTER \
|
||||
(defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 5) && (_WRS_VXWORKS_MINOR >= 1)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 5) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_5_3_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 5) && (_WRS_VXWORKS_MINOR >= 3)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 5) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_5_4_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 5) && (_WRS_VXWORKS_MINOR >= 4)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 5) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_6_0_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 0)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 6) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_6_1_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 1)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 6) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_6_3_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 3)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 6) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_6_4_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 4)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 6) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_6_6_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 6) ) \
|
||||
)
|
||||
|
||||
#define VXWORKS_VERSION_6_7_OR_BETTER \
|
||||
( defined(RTI_VXWORKS) && ( \
|
||||
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 7)) || \
|
||||
(_WRS_VXWORKS_MAJOR > 6) ) \
|
||||
)
|
||||
|
||||
#endif /* vxversions_h */
|
||||
@@ -0,0 +1,44 @@
|
||||
/* std_fcns.h - */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
std_fcns.h
|
||||
This file simply implements some definitions for a (random) collection of
|
||||
VxWorks calls that aren't prototyped in the regular include files. Types
|
||||
which may not always be defined are commented out, rather than force
|
||||
inclusion of a bunch of unecessary include files.
|
||||
|
||||
Written by: Stan Schneider, Stanford, June 1990
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
/* defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern unsigned int sleep(unsigned int secs);
|
||||
#ifdef OLD
|
||||
extern unsigned int usleep(unsigned int usecs);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
# Makefile - makefile for building scopetools rti library
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01b,01nov10,pca Exclude unnecessary objects from LP64 builds
|
||||
# 01a,26mar08,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the rti library
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../..
|
||||
|
||||
DOC_FILES =
|
||||
|
||||
# Including defs.library to see VSB defines _WRS_CONFIG_SMP/LP64.
|
||||
include $(TGT_DIR)/h/make/defs.library
|
||||
|
||||
ifndef _WRS_CONFIG_LP64
|
||||
SUBDIRS = syserr osapi fastBuffer matlabls netio query
|
||||
else
|
||||
SUBDIRS = syserr osapi netio
|
||||
endif
|
||||
|
||||
include $(TGT_DIR)/h/make/rules.library
|
||||
include $(TOOLS_SRC_ROOT)/make/header.mk
|
||||
@@ -0,0 +1,34 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,26mar06,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../../..
|
||||
|
||||
LIB_BASE_NAME = rtilib
|
||||
|
||||
EXTRA_DEFINE += -DRTS_VXWORKS -DPtrIntType=long
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= fastBuffer.o
|
||||
|
||||
HDR_PATH = ../../include/share/rtilib
|
||||
HEADERS = $(HDR_PATH)/fastBuffer.h
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
###
|
||||
# Public header generation
|
||||
|
||||
$(HDR_PATH)/fastBuffer.h : fastBuffer.c
|
||||
$(MAKEHEADER) -C $(MAKEHEADERPUBKEYS) -o $@ $^
|
||||
|
||||
# end of rtilib/utils/fastBuffer
|
||||
@@ -0,0 +1,706 @@
|
||||
/* fastBuffer.c - Brief Fast memory access routines for FIXED-size buffers */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990-2009,2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01b,30oct13,elp Ignore RtiSemaphoreTake return value in ISRlock().
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
4.4a,31may07,mas Made VxWorks SMP compliant; made lock/unlock OS agnostic.
|
||||
4.0d,03jul00,gah fixed bug where fastBuffer pools were not byte aligned.
|
||||
4.0c,04apr00,sst Replaced semaphore.pkg.h with semaphore_common.pkg.h
|
||||
3.9e,16apr99,hhw Fixed bug in which semaphore being used before creation
|
||||
in FastBufferCreatePool().
|
||||
3.9e,12apr99,laf Made FastBuffer threads-safe for Unix.
|
||||
RTI, 24jul96,mlh Updated man pages.
|
||||
RTI, 11mar96,gpc Added header and distribution information to man pages
|
||||
RTI, 18dec95,sda Changed private, public, package to Private, Public, Package.
|
||||
Cleaned up comments.
|
||||
rti, 14jul95,vwc Give FastBuffer the capability to allocate more pools
|
||||
rti, 24mar93,sas Sentinelized. Changed xxfastBuffer to FastBufferxx.
|
||||
rti, 28feb93,sas Updated docs.
|
||||
rti, 24feb93,vwc Converted to mangen format. Wrote man page docs.
|
||||
rti, 10Feb90,vwc Written
|
||||
*/
|
||||
/* $Id: fastBuffer.c,v 1.36 2007/11/17 00:57:38 mstanek Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
defgroup fastBuf FastBuffer
|
||||
|
||||
FastBuffer provides a pool of FIXED-size memory buffers that can be
|
||||
used for fast allocation/deallocation at run-time.
|
||||
|
||||
The normal memory-allocation routines (such as malloc and free) are
|
||||
relatively slow routines and may be too time-consuming for real-time
|
||||
tasks. By using FastBuffer, real-time tasks can access memory quickly.
|
||||
|
||||
To use it, first call FastBufferCreatePool (typically during
|
||||
initialization). This will allocate a specified number of buffers,
|
||||
each of a specified size. At run time, a task can grab a buffer
|
||||
by calling FastBufferGet and return it by calling FastBufferReturn.
|
||||
|
||||
If, when using FastBufferGet, FastBuffer runs out of buffers,
|
||||
you can call FastBufferAddPool to allocate additional pools. The size of
|
||||
the new pool will be TWICE the size of the previously allocated pool.
|
||||
A maximum of 10 pools will be allocated before FastBuffer returns
|
||||
NULL to indicate error. This means that the total size managed by
|
||||
FastBuffer can reach (2^10-1)*nBuffers!! Also, because of concurrency
|
||||
issues, the tool *MUST* disable operation before calling this routine.
|
||||
|
||||
NOTE: FastBufferAddPool, FastBufferDestroyPool, and all other routines in
|
||||
this library which actively allocate and/or free memory cannot be called
|
||||
from within an ISR! An error will be returned if the attempt is made.
|
||||
Also, because of concurrency issues, any tool calling these routines *MUST*
|
||||
disable operation before calling them.
|
||||
|
||||
FastBufferReturn will not dynamically shrink the number of pools, but
|
||||
FastBufferClearPool will free up the memory used by additional pools
|
||||
dynamically allocated by FastBufferGet.
|
||||
|
||||
\b Example:
|
||||
\code
|
||||
FastBufferID fastBuf;
|
||||
typedef struct {
|
||||
...
|
||||
} *myType, myTypeStorage;
|
||||
int initialize( void )
|
||||
{
|
||||
fastBuf = FastBufferCreatePool(100, sizeof(myTypeStorage));
|
||||
...
|
||||
}
|
||||
void task( void )
|
||||
{
|
||||
myType var1, var2;
|
||||
...
|
||||
var1 = FastBufferGet(fastBuf);
|
||||
var2 = FastBufferGet(fastBuf);
|
||||
|
||||
...
|
||||
|
||||
FastBufferReturn(var1);
|
||||
FastBufferReturn(var2);
|
||||
...
|
||||
}
|
||||
\endcode
|
||||
\b Header \b Files
|
||||
\verbatim
|
||||
#include "rtilib/fastBuffer.h"
|
||||
\endverbatim
|
||||
|
||||
The location of the header files depends on your distribution:
|
||||
<pre>
|
||||
Distribution Include Path
|
||||
~~~~~~~~~~~~ ~~~~~~~~~~~~
|
||||
Stand-alone -I/$(RTILIBHOME)/include/<os>
|
||||
-I/$(RTILIBHOME)/include/share
|
||||
Tornado -I/$(WIND_BASE)/target/h
|
||||
</pre>
|
||||
where <os> can be "unix" (to build for Unix), "vx" (to build for VxWorks),
|
||||
or "win32" (to build for (WindowsNT or Windows95).
|
||||
|
||||
\b Libraries
|
||||
|
||||
This library is distributed both stand-alone and as part of RTI's LibUtils
|
||||
package. Therefore, you can either link this library only or to the complete
|
||||
LibUtils. This is illustrated in the following table.
|
||||
<pre>
|
||||
TOS This Library Only LibUtils
|
||||
~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~
|
||||
Unix rtilibcomps/libfastBuffer.a libutils.a
|
||||
VxWorks rtilibcomps/fastBuffer.so libutilsip.so
|
||||
Windows no stand-alone lib libutils.lib
|
||||
<pre>
|
||||
The location of the libaries depends on your distribution:
|
||||
<pre>
|
||||
Distribution Library Location
|
||||
~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Stand-alone /$(RTILIBHOME)/lib/<tArch>
|
||||
Tornado /$(WIND_BASE)/target/lib/rtilib/<tArch>
|
||||
</pre>
|
||||
In this table, <tArch> can be any of the target architectures in your
|
||||
distribution (e.g. "m68kVx5.2" for a Motorola 68k processor running
|
||||
VxWorks 5.2, "i86Win32" for an intel X86 processor running Windows [NT or 95]).
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtilib/makeheader.h>
|
||||
#pragma begin_Public
|
||||
# include <rtilib/rti_types.h>
|
||||
#pragma end_Public
|
||||
#include <rtilib/rti_semaphore.h>
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
# include <vxWorks.h>
|
||||
# include <rtilib/stSpinLock.h>
|
||||
|
||||
# define lock(x) task_lock(&x->key)
|
||||
# define unlock(x) task_unlock(&x->key)
|
||||
# define ISRlock(x) isr_lock(&x->lock)
|
||||
# define ISRunlock(x) isr_unlock(&x->lock)
|
||||
#else
|
||||
# define lock(x) \
|
||||
((RtiSemaphoreTake(x->fastBufferSemID,NULL) == RTI_SEMAPHORE_OK) ? \
|
||||
RTI_TRUE : RTI_FALSE)
|
||||
# define unlock(x) \
|
||||
((RtiSemaphoreGive(x->fastBufferSemID) == RTI_SEMAPHORE_OK) ? \
|
||||
RTI_TRUE : RTI_FALSE)
|
||||
# define ISRlock(x) (void)RtiSemaphoreTake(x->fastBufferSemID, NULL)
|
||||
# define ISRunlock(x) RtiSemaphoreGive(x->fastBufferSemID)
|
||||
#endif
|
||||
|
||||
#define MAX_POOLS (10)
|
||||
|
||||
/* Debug information. Define the following for debugging. */
|
||||
#undef FAST_BUFFER_DEBUG
|
||||
#define VALID_FAST_BUF 0xfacedeaf
|
||||
|
||||
Public typedef struct FastBufferTag *FastBufferID;
|
||||
|
||||
/*e
|
||||
\ingroup fastBuf
|
||||
@brief Strucutre of fastBuffer elements.
|
||||
*/
|
||||
typedef struct FastBufferTag {
|
||||
void * StartOfArray[MAX_POOLS]; /** array of (top of array of
|
||||
pool space) */
|
||||
int bufSize; /** buffer size */
|
||||
int nBuffers; /** number of buffers */
|
||||
int nPools; /** number of pools allocated */
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
/* Only two of the API routines in this library may be called
|
||||
* from within an ISR: FastBufferGet() and FastBufferReturn().
|
||||
* An isr_lock() is used to protect these calls against all
|
||||
* callers, including ISRs.
|
||||
*
|
||||
* All other routines cannot be called from within ISRs, so
|
||||
* they are protected against other calling tasks by simple
|
||||
* preemption spin locks.
|
||||
*/
|
||||
st_preemptLock key; /* locks against other tasks */
|
||||
st_isrLock lock; /* locks against any other caller */
|
||||
#else
|
||||
RTISemaphoreId fastBufferSemID;
|
||||
#endif
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
uint32_t cookie;
|
||||
#endif
|
||||
|
||||
void ** sp; /** stack pointer */
|
||||
void ** stackTop;
|
||||
void ** stackBottom;
|
||||
} FastBufferStorage;
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*i \ingroup fastBuf
|
||||
|
||||
@brief Actual work routine for clearing the Pools
|
||||
|
||||
This function takes a flag of either resetting the stack pointers
|
||||
for only the first pool (when a new pool is added dynamically) or
|
||||
resetting all the pools (when FastBufferClearPool is explicitly called.)
|
||||
|
||||
Note that the flag does not mean much anymore, since FastBufferClearPool
|
||||
always frees the additional pools.
|
||||
*/
|
||||
Private
|
||||
void clearPool( FastBufferID poolID, int doAll )
|
||||
{
|
||||
register void **ptr;
|
||||
register size_t j, n;
|
||||
register int i;
|
||||
int firstPool = 0;
|
||||
|
||||
/* Get powers of 2, depending on number of pools */
|
||||
n = (1 << (poolID->nPools - 1)) * poolID->nBuffers;
|
||||
|
||||
if (!doAll) { firstPool = poolID->nPools - 1; }
|
||||
|
||||
ptr = poolID->stackBottom;
|
||||
|
||||
for (i = poolID->nPools - 1; i >= firstPool; i--, n /= 2) {
|
||||
/* Point to end of pool */
|
||||
*ptr = (void*) (((size_t) poolID->StartOfArray[i]) +
|
||||
(n - 1) * (poolID->bufSize + sizeof(FastBufferID)) +
|
||||
sizeof(FastBufferID) );
|
||||
|
||||
for (j = 0; j < n - 1 && ptr <= poolID->stackTop; j++, ptr++) {
|
||||
*(ptr + 1) = (void*) (((size_t) *(ptr)) -
|
||||
(poolID->bufSize + sizeof(FastBufferID)));
|
||||
}
|
||||
}
|
||||
poolID->sp = ptr;
|
||||
}
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Creates memory for a pool.
|
||||
|
||||
Whenever this function is called, it allocates a new pool. If
|
||||
the maximum size has been reached, it returns NULL. The new pool
|
||||
size will have twice the number of buffers as the previously
|
||||
allocated one, making the total number of buffers be
|
||||
|
||||
(2^n - 1) * nBuffers
|
||||
|
||||
This function also creates a new stack that can hold the pointers
|
||||
for all the buffers.
|
||||
|
||||
It calls clearPool() to clear only the newly allocated pool.
|
||||
|
||||
It must not be called from an ISR! If it is, a NULL is returned and
|
||||
errno is set.
|
||||
|
||||
This routine must never be called if there are any outstanding buffers
|
||||
still in use! This routine must be called after a tool has paused
|
||||
operation.
|
||||
|
||||
RETURNS: address of new pool or NULL if error.
|
||||
|
||||
ERRNO: S_intLib_NOT_ISR_CALLABLE
|
||||
*/
|
||||
Public DllExport
|
||||
void *FastBufferAddPool( FastBufferID poolID )
|
||||
{
|
||||
int i, n = 1, sz, stkSz, bufSz, nPools;
|
||||
void * ptr;
|
||||
void * newBuf;
|
||||
void * stackBottom;
|
||||
void ** newStack;
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
if (INT_RESTRICT() != OK) { return (NULL); }
|
||||
#endif
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
if (poolID->cookie != VALID_FAST_BUF) { return (NULL); }
|
||||
#endif
|
||||
if (poolID->nPools >= MAX_POOLS) { return (NULL); }
|
||||
|
||||
(void)lock(poolID);
|
||||
|
||||
nPools = poolID->nPools;
|
||||
if (nPools >= MAX_POOLS) {
|
||||
(void)unlock(poolID);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Get powers of 2, depending on number of pools */
|
||||
n = 1 << nPools;
|
||||
bufSz = poolID->bufSize;
|
||||
stackBottom = poolID->stackBottom;
|
||||
sz = (n * poolID->nBuffers);
|
||||
stkSz = (2 * n - 1) * poolID->nBuffers;
|
||||
|
||||
newBuf = (void*) malloc (sz * (sizeof(FastBufferID) + bufSz));
|
||||
if (newBuf == NULL) {
|
||||
(void)unlock(poolID);
|
||||
return (NULL);
|
||||
}
|
||||
newStack = (void **) malloc (stkSz * sizeof(void *));
|
||||
if (newStack == NULL) {
|
||||
free (newBuf);
|
||||
newBuf = NULL;
|
||||
} else {
|
||||
if (stackBottom != NULL) { free (stackBottom); }
|
||||
|
||||
ptr = newBuf;
|
||||
for (i = 0; i < n * poolID->nBuffers; i++) {
|
||||
*((FastBufferID *) ptr) = poolID;
|
||||
ptr = (void*) (((size_t)ptr) + poolID->bufSize +
|
||||
sizeof(FastBufferID));
|
||||
}
|
||||
|
||||
poolID->StartOfArray[nPools] = newBuf;
|
||||
++poolID->nPools;
|
||||
poolID->stackBottom = newStack;
|
||||
poolID->stackTop = newStack + stkSz - 1;
|
||||
|
||||
/* Clear only new pool */
|
||||
clearPool (poolID, 0);
|
||||
}
|
||||
|
||||
(void)unlock(poolID);
|
||||
|
||||
return (newBuf);
|
||||
}
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Clears the fast buffer pool.
|
||||
|
||||
FastBufferClearPool clears the specified fast buffer by resetting the
|
||||
internal pointers. All buffers should be considered "deallocated".
|
||||
All additional memory pools that were added automatically will be
|
||||
freed.
|
||||
|
||||
It must not be called from an ISR! If it is, errno is set and the pool
|
||||
is not cleared.
|
||||
|
||||
This routine must never be called if there are any outstanding buffers
|
||||
still in use! This routine must be called either when shutting down a
|
||||
tool or after a tool has paused operation.
|
||||
|
||||
RETURNS: N/A
|
||||
|
||||
ERRNO: S_intLib_NOT_ISR_CALLABLE
|
||||
*/
|
||||
Public DllExport
|
||||
void FastBufferClearPool( FastBufferID poolID )
|
||||
{
|
||||
register int i, sz;
|
||||
void **newStack;
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
if (INT_RESTRICT() != OK) { return; }
|
||||
#endif
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
if (poolID->cookie != VALID_FAST_BUF) { return; }
|
||||
#endif
|
||||
|
||||
(void)lock(poolID); /* probably safe to ignore lock failure here */
|
||||
|
||||
if (poolID->nPools > 1) {
|
||||
for (i = poolID->nPools - 1; i > 0; i--) {
|
||||
free(poolID->StartOfArray[i]);
|
||||
poolID->StartOfArray[i] = NULL;
|
||||
}
|
||||
poolID->nPools = 1;
|
||||
|
||||
sz = poolID->nBuffers;
|
||||
newStack = (void **) malloc (sz * sizeof(void *));
|
||||
if (newStack == NULL) {
|
||||
fprintf(stderr, "FastBufferClearPool warning: malloc failure\n");
|
||||
} else {
|
||||
if (poolID->stackBottom) { free(poolID->stackBottom); }
|
||||
poolID->stackBottom = newStack;
|
||||
}
|
||||
poolID->stackTop = poolID->stackBottom + sz - 1;
|
||||
}
|
||||
|
||||
/* Call work routine to clear all pools */
|
||||
clearPool(poolID, 1);
|
||||
|
||||
(void)unlock(poolID);
|
||||
}
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Creates a fast buffer pool.
|
||||
|
||||
|
||||
FastBufferCreatePool creates a set of fast buffers and returns
|
||||
a handle to a "FastBufferID". This ID can be used to allocate
|
||||
and free individual buffers from the pool. The caller supplies
|
||||
the number of buffers and the buffer size. The memory for the
|
||||
new buffer pool is obtained via "malloc".
|
||||
|
||||
Note that "nBuffers" is the initial number of buffers. FastBufferGet
|
||||
will automatically add pools of buffers (size growing in powers
|
||||
of two) when it runs out of buffers. FastBufferClearPool will
|
||||
free these additional pools (and clear the pool).
|
||||
|
||||
Also note that "nBuffers" must be divisable by the size of a pointer
|
||||
for the architecture. This is enforced and if not true, the number
|
||||
of buffers is increased to satisfy this condition.
|
||||
|
||||
It must not be called from an ISR! If it is, a NULL is returned and
|
||||
errno is set.
|
||||
|
||||
RETURNS
|
||||
On failure, it returns NULL if not enough memory.
|
||||
On success, it returns a handle to the fast buffer set.
|
||||
|
||||
ERRNO: S_intLib_NOT_ISR_CALLABLE
|
||||
*/
|
||||
Public DllExport
|
||||
FastBufferID FastBufferCreatePool ( int nBuffers, int bufSize )
|
||||
{
|
||||
|
||||
FastBufferID poolID;
|
||||
register int i;
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
if (INT_RESTRICT() != OK) { return (NULL); }
|
||||
#endif
|
||||
|
||||
poolID = (FastBufferID) malloc (sizeof(FastBufferStorage));
|
||||
if (poolID == NULL) {
|
||||
fprintf(stderr, "FastBufferCreatePool error: malloc failure\n");
|
||||
return(NULL);
|
||||
}
|
||||
poolID->bufSize = bufSize + (bufSize%sizeof(FastBufferID));
|
||||
poolID->nBuffers = nBuffers;
|
||||
|
||||
poolID->nPools = 0;
|
||||
for (i = 0; i < MAX_POOLS; i++) {
|
||||
poolID->StartOfArray[i] = NULL;
|
||||
}
|
||||
poolID->sp = NULL;
|
||||
poolID->stackTop = NULL;
|
||||
poolID->stackBottom = NULL;
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
if (!task_lock_init (&poolID->key)) {
|
||||
free (poolID);
|
||||
return (NULL);
|
||||
}
|
||||
isr_lock_init (&poolID->lock);
|
||||
#else
|
||||
poolID->fastBufferSemID = RtiSemaphoreBinaryNew(RTI_SEMAPHORE_Q_FIFO,
|
||||
RTI_SEMAPHORE_FULL);
|
||||
if (poolID->fastBufferSemID == NULL) {
|
||||
free(poolID);
|
||||
return(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (FastBufferAddPool(poolID) == NULL) {
|
||||
fprintf(stderr, "FastBufferCreatePool error: malloc failure\n");
|
||||
free(poolID);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
poolID->cookie = VALID_FAST_BUF;
|
||||
#endif
|
||||
|
||||
return poolID;
|
||||
}
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Destroys a fast buffer pool.
|
||||
|
||||
FastBufferDestroyPool destroys a fast buffer pool, returning the
|
||||
used memory.
|
||||
|
||||
It must not be called from an ISR! If it is, errno is set and the
|
||||
pool remains intact.
|
||||
|
||||
This routine must never be called if there are any outstanding buffers
|
||||
still in use! This routine must be called either when shutting down a
|
||||
tool or after a tool has paused operation.
|
||||
|
||||
RETURNS: N/A
|
||||
|
||||
ERRNO: S_intLib_NOT_ISR_CALLABLE
|
||||
*/
|
||||
Public DllExport
|
||||
void FastBufferDestroyPool ( FastBufferID poolID )
|
||||
{
|
||||
register int i;
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
if (INT_RESTRICT() != OK) { return; }
|
||||
#endif
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
if (poolID->cookie != VALID_FAST_BUF) { return; }
|
||||
#endif
|
||||
|
||||
/* TD: can remove lock if proven not necessary */
|
||||
(void)lock(poolID);
|
||||
|
||||
free(poolID->stackBottom);
|
||||
for (i = 0; i < poolID->nPools; i++) {
|
||||
free(poolID->StartOfArray[i]);
|
||||
}
|
||||
|
||||
(void)unlock(poolID);
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
/* done with locks so release them */
|
||||
isr_lock_init (&poolID->lock);
|
||||
task_lock_done (&poolID->key);
|
||||
#else
|
||||
RtiSemaphoreDelete(poolID->fastBufferSemID);
|
||||
#endif
|
||||
|
||||
free(poolID);
|
||||
}
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Gets the next available fast buffer.
|
||||
|
||||
FastBufferGet returns a pointer to the next available fast buffer. This
|
||||
routine is extremely fast, and may be called from interrupt service
|
||||
routines, etc.
|
||||
|
||||
If you want to allocate more buffers, call FastBufferAddPool. If
|
||||
you are not using buffers in an interrupt-service routine, you
|
||||
can use FastBufferGetAutoAddPool to automatically increase
|
||||
buffer pool, but only after pausing the tool.
|
||||
|
||||
RETURNS
|
||||
Pointer to buffer, else, NULL if there are no more buffers.
|
||||
*/
|
||||
Public DllExport
|
||||
void *FastBufferGet ( FastBufferID poolID )
|
||||
{
|
||||
void *buffer;
|
||||
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
if (poolID->cookie != VALID_FAST_BUF) { return (NULL); }
|
||||
#endif
|
||||
ISRlock(poolID);
|
||||
|
||||
if (poolID->sp >= poolID->stackBottom) {
|
||||
buffer= *((poolID->sp)--);
|
||||
} else {
|
||||
buffer= NULL;
|
||||
}
|
||||
|
||||
ISRunlock(poolID);
|
||||
|
||||
return(buffer);
|
||||
}
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Gets the next available fast buffer, adding more buffers if needed.
|
||||
|
||||
FastBufferGetAutoAddPool returns a pointer to the next available
|
||||
fast buffer. If it runs out of buffers, it automatically calls
|
||||
FastBufferAddPool to get additional buffers. This routine is
|
||||
extremely fast, and may be called from interrupt service
|
||||
routines, EXCEPT when it goes to allocate more pools.
|
||||
|
||||
If FastBuffer runs out of memory this call WILL MALLOC MORE MEMORY
|
||||
so that it can dynamically grow to suit your application. But if
|
||||
you are using FastBuffer inside interrupt service routines, and it
|
||||
is critical that malloc not be called, specify a large enough initial
|
||||
size when creating the FastBuffer, or use the FastBufferGet call
|
||||
instead.
|
||||
|
||||
Additional buffers are added in powers of 2. Each new pool of buffers
|
||||
is twice as large as the previous pool. That is, the total
|
||||
number of buffers will be:
|
||||
|
||||
(2^n - 1) * nBuffers
|
||||
|
||||
where "n" is the number of pools. A maximum of 10 pools will be
|
||||
allowed.
|
||||
|
||||
This routine must never be called if there are any outstanding buffers
|
||||
still in use! This routine must be called after a tool has paused
|
||||
operation.
|
||||
|
||||
RETURNS: Pointer to new buffer, else, NULL if no more buffers or if
|
||||
called from ISR when allocation was required.
|
||||
|
||||
ERRNO: S_intLib_NOT_ISR_CALLABLE
|
||||
*/
|
||||
Public DllExport
|
||||
void *FastBufferGetAutoAddPool ( FastBufferID poolID )
|
||||
{
|
||||
void *buffer = NULL;
|
||||
|
||||
if ((buffer = FastBufferGet(poolID)) == NULL) {
|
||||
if (FastBufferAddPool(poolID) != NULL) {
|
||||
buffer = FastBufferGet(poolID);
|
||||
}
|
||||
}
|
||||
return(buffer);
|
||||
}
|
||||
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Returns a fast buffer to the pool.
|
||||
|
||||
FastBufferReturn returns the buffer to the buffer pool. This routine is
|
||||
also very fast, and may be called from interrupt code.
|
||||
*/
|
||||
Public DllExport
|
||||
void FastBufferReturn ( void *buffer )
|
||||
{
|
||||
FastBufferID poolID;
|
||||
|
||||
poolID = *(((FastBufferID *) ( buffer)) - 1);
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
if (poolID->cookie != VALID_FAST_BUF) { return; }
|
||||
#endif
|
||||
|
||||
ISRlock(poolID);
|
||||
|
||||
*(++(poolID->sp)) = buffer;
|
||||
|
||||
ISRunlock(poolID);
|
||||
}
|
||||
|
||||
/* ===================================================================== */
|
||||
/*e \ingroup fastBuf
|
||||
|
||||
@brief Displays (to stdout) fastBuffer information.
|
||||
|
||||
When called, outputs the current buffer size, number of elements, number
|
||||
of pools, and associated pointers.
|
||||
|
||||
It must not be called from an ISR!
|
||||
|
||||
RETURNS: N/A
|
||||
|
||||
ERRNO: S_intLib_NOT_ISR_CALLABLE
|
||||
*/
|
||||
Public DllExport
|
||||
void FastBufferDisplay( FastBufferID poolID )
|
||||
{
|
||||
register int i;
|
||||
void **ptr;
|
||||
|
||||
#if defined(RTS_VXWORKS) && !defined(__RTP__)
|
||||
if (INT_RESTRICT() != OK) { return; }
|
||||
#endif
|
||||
#ifdef FAST_BUFFER_DEBUG
|
||||
if (poolID->cookie != VALID_FAST_BUF) { return; }
|
||||
#endif
|
||||
|
||||
printf("FastBuffer at 0x%p\n", poolID);
|
||||
printf(" Buffer Size: %d\n", poolID->bufSize);
|
||||
printf(" Number of Buffers: %d\n", poolID->nBuffers);
|
||||
printf(" Stack Pointer: 0x%p\n", poolID->sp);
|
||||
printf(" Stack Top: 0x%p\n", poolID->stackTop);
|
||||
printf(" Stack Bottom: 0x%p\n", poolID->stackBottom);
|
||||
|
||||
printf("\n MemoryPools (%d):\n", poolID->nPools);
|
||||
for (i = 0; i < poolID->nPools; i++) {
|
||||
printf(" 0x%p (%uld)\n", poolID->StartOfArray[i],
|
||||
(unsigned int) (1L << i) * poolID->nBuffers);
|
||||
}
|
||||
|
||||
printf("\n Stack:\n");
|
||||
ptr = poolID->stackBottom;
|
||||
i = 0;
|
||||
while (ptr <= poolID->stackTop) {
|
||||
printf(" 0x%p (0x%p) (%d) %d\n", *ptr, ptr,
|
||||
(ptr > poolID->sp) ? 1 : 0, i);
|
||||
++ptr; ++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,26mar06,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../../..
|
||||
|
||||
LIB_BASE_NAME = matlabls
|
||||
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= loadmat.o savemat.o testls.o
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
# end of rtilib/utils/matlabls
|
||||
@@ -0,0 +1,140 @@
|
||||
/* loadmat.c - brief C language routine to load a matrix from a MAT-file. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990-2009, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
-------------------
|
||||
01c,10oct13,wzc Fix prevent warnings.
|
||||
01b,29jun12,wzc WIND00350881 - check malloc return value.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
01a,30jun09,wzc fix coverity prevent errors
|
||||
Converted to ANSI-C, Stan Schneider, 1990
|
||||
Author J.N. Little 11-3-86
|
||||
*/
|
||||
/* $Id: loadmat.c,v 1.6 2002/07/03 00:11:54 gordon Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Brief C language routine to load a matrix from a MAT-file.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "rtilib/makeheader.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
typedef struct {
|
||||
long type; /* type */
|
||||
long mrows; /* row dimension */
|
||||
long ncols; /* column dimension */
|
||||
long imagf; /* flag indicating imag part */
|
||||
long namlen; /* name length (including NULL) */
|
||||
} Fmatrix;
|
||||
|
||||
|
||||
Public
|
||||
/*i
|
||||
|
||||
Here is an example that uses 'loadmat' to load a matrix from a MAT-file:
|
||||
|
||||
\verbatim
|
||||
FILE *fp;
|
||||
char name[20];
|
||||
int type, mrows, ncols, imagf;
|
||||
double *xr, *xi;
|
||||
fp = fopen("foo.mat","r");
|
||||
loadmat(fp, &type, name, &mrows, &ncols, &imagf, &xr, &xi);
|
||||
fclose(fp);
|
||||
free(xr);
|
||||
if (imagf) free(xi);
|
||||
\endverbatim
|
||||
|
||||
The 'loadmat' routine returns 0 if the read is successful and 1 if
|
||||
and end-of-file or read error is encountered. 'loadmat' can be called
|
||||
repeatedly until the file is exhausted and an EOF is encountered.
|
||||
*/
|
||||
|
||||
int loadmat(
|
||||
FILE *fp, /* File pointer */
|
||||
int *type, /* Type flag: see reference section of guide */
|
||||
char *pname, /* pointer to matrix name */
|
||||
int *mrows, /* row dimension */
|
||||
int *ncols, /* column dimension */
|
||||
int *imagf, /* imaginary flag */
|
||||
double **preal, /* pointer to real data */
|
||||
double **pimag) /* pointer to imag data */
|
||||
{
|
||||
Fmatrix x = {0,0,0,0,0};
|
||||
size_t mn;
|
||||
size_t namlen;
|
||||
size_t len;
|
||||
/*
|
||||
* Get Fmatrix structure from file
|
||||
*/
|
||||
if (fread((char *)&x, sizeof(Fmatrix), 1, fp) != 1) {
|
||||
return(1);
|
||||
}
|
||||
/* coverity[parm_assign] */
|
||||
*type = (int)(x.type);
|
||||
/* coverity[parm_assign] */
|
||||
*mrows = (int)(x.mrows);
|
||||
/* coverity[parm_assign] */
|
||||
*ncols = (int)(x.ncols);
|
||||
/* coverity[parm_assign] */
|
||||
*imagf = (int)(x.imagf);
|
||||
/* coverity[parm_assign] */
|
||||
namlen = (size_t)(x.namlen);
|
||||
/* coverity[overflow_assign] */
|
||||
mn = (size_t)(x.mrows * x.ncols);
|
||||
|
||||
/*
|
||||
* Get matrix name from file
|
||||
*/
|
||||
if (fread(pname, sizeof(char), namlen, fp) != namlen) {
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Real part of matrix from file
|
||||
*/
|
||||
/* coverity[overflow_assign] */
|
||||
len = (size_t)(mn*sizeof(double));
|
||||
*preal = (double *)malloc(len);
|
||||
if (!(*preal)) {
|
||||
printf("\nError: Variable too big to load\n");
|
||||
return(1);
|
||||
}
|
||||
if (fread(*preal, sizeof(double), mn, fp) != mn) {
|
||||
free(*preal);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Imag part of matrix from file, if it exists
|
||||
*/
|
||||
if (x.imagf) {
|
||||
*pimag = (double *)malloc(len);
|
||||
if (!(*pimag)) {
|
||||
printf("\nError: Variable too big to load\n");
|
||||
free(*preal);
|
||||
return(1);
|
||||
}
|
||||
if (fread(*pimag, sizeof(double), mn, fp) != mn) {
|
||||
free(*pimag);
|
||||
free(*preal);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,24 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
# modification history
|
||||
|
||||
# --------------------
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# $Id: matlablsh.win32,v 1.3 2004/06/08 17:53:51 rwarren Exp $
|
||||
|
||||
|
||||
|
||||
DIR = .
|
||||
|
||||
|
||||
|
||||
matlablshSources = loadmat.c savemat.c
|
||||
|
||||
|
||||
|
||||
../../include/win32/rtilib/matlabls.h : $(matlablshSources)
|
||||
|
||||
makeheader -C -k Public -o $@ $^
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* savemat.c - brief C language routine to save a matrix from a MAT-file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990-2009 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
---------------------
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
Converted to ANSI-C, Stan Schneider, 1990
|
||||
Author J.N. Little 11-3-86
|
||||
*/
|
||||
/* $Id: savemat.c,v 1.4 2002/07/03 00:11:54 gordon Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
brief C language routine to save a matrix from a MAT-file.
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "rtilib/makeheader.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
typedef struct {
|
||||
long type; /* type */
|
||||
long mrows; /* row dimension */
|
||||
long ncols; /* column dimension */
|
||||
long imagf; /* flag indicating imag part */
|
||||
long namlen; /* name length (including NULL) */
|
||||
} Fmatrix;
|
||||
|
||||
Public
|
||||
/*i
|
||||
|
||||
Here is an example that uses 'savemat' to save two matrices to disk,
|
||||
the second of which is complex:
|
||||
|
||||
/verbatim
|
||||
FILE *fp;
|
||||
double xyz[1000], ar[1000], ai[1000];
|
||||
fp = fopen("foo.mat","w");
|
||||
savemat(fp, 2000, "xyz", 2, 3, 0, xyz, (double *)0);
|
||||
savemat(fp, 2000, "a", 5, 5, 1, ar, ai);
|
||||
fclose(fp);
|
||||
/endverbatim
|
||||
*/
|
||||
void savemat(
|
||||
FILE *fp, /* File pointer */
|
||||
int type, /* Type flag: Normally 0 for PC, 1000 for Sun and Mac, */
|
||||
/* 2000 for VAX. Add 1 for text variables. */
|
||||
/* See LOAD in reference section of guide for more info. */
|
||||
char *pname, /* pointer to matrix name */
|
||||
int mrows, /* row dimension */
|
||||
int ncols, /* column dimension */
|
||||
int imagf, /* imaginary flag */
|
||||
double *preal, /* pointer to real data */
|
||||
double *pimag) /* pointer to imag data */
|
||||
{
|
||||
Fmatrix x;
|
||||
int mn;
|
||||
|
||||
x.type = type;
|
||||
x.mrows = mrows;
|
||||
x.ncols = ncols;
|
||||
x.imagf = imagf;
|
||||
x.namlen = strlen(pname) + 1;
|
||||
mn = x.mrows * x.ncols;
|
||||
|
||||
fwrite(&x, sizeof(Fmatrix), 1, fp);
|
||||
fwrite(pname, sizeof(char), (int)x.namlen, fp);
|
||||
fwrite(preal, sizeof(double), mn, fp);
|
||||
if (imagf) {
|
||||
fwrite(pimag, sizeof(double), mn, fp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/* testls.c - */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2009, 2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01c,12oct13,wzc Fix prevent warnings.
|
||||
01b,21jun13,wzc WIND00422900 - fix prevent warnings.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
A C-language version test routine that shows the use of the
|
||||
C-language 'loadmat' and 'savemat' to read and write MAT-files.
|
||||
|
||||
Author: J.N. Little 11-10-86
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
extern int loadmat(
|
||||
FILE *fp, /* File pointer */
|
||||
int *type, /* Type flag: see reference section of guide */
|
||||
char *pname, /* pointer to matrix name */
|
||||
int *mrows, /* row dimension */
|
||||
int *ncols, /* column dimension */
|
||||
int *imagf, /* imaginary flag */
|
||||
double **preal, /* pointer to real data */
|
||||
double **pimag);
|
||||
|
||||
extern void savemat(
|
||||
FILE *fp, /* File pointer */
|
||||
int type, /* Type flag: Normally 0 for PC, 1000 for Sun and Mac, */
|
||||
/* 2000 for VAX. Add 1 for text variables. */
|
||||
/* See LOAD in reference section of guide for more info. */
|
||||
char *pname, /* pointer to matrix name */
|
||||
int mrows, /* row dimension */
|
||||
int ncols, /* column dimension */
|
||||
int imagf, /* imaginary flag */
|
||||
double *preal, /* pointer to real data */
|
||||
double *pimag);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
FILE *fp, *fopen();
|
||||
char name[20] = {0};
|
||||
int type, mrows, ncols, imagf;
|
||||
double *xr, *xi;
|
||||
|
||||
/*
|
||||
* Use this fopen on systems that do newline translation, for
|
||||
* example C86 compiler under MS-DOS
|
||||
*
|
||||
* fp = fopen("foo.mat","rb");
|
||||
*/
|
||||
fp = fopen("foo.mat","r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("\nfopen error\n");
|
||||
return -1;
|
||||
}
|
||||
/* coverity[tainted_data] */
|
||||
if (loadmat(fp, &type, &name[0], &mrows, &ncols, &imagf, &xr, &xi)) {
|
||||
printf("\nRead error\n");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/*
|
||||
* fp = fopen("bar.mat","wb");
|
||||
*/
|
||||
fp = fopen("bar.mat","w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("\nfopen error\n");
|
||||
return -1;
|
||||
}
|
||||
/* coverity[tainted_data] */
|
||||
savemat(fp, type, &name[0], mrows, ncols, imagf, xr, xi);
|
||||
fclose(fp);
|
||||
free(xr);
|
||||
if (imagf) {
|
||||
free(xi);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# Makefile - makefile for target/src/scopetools
|
||||
#
|
||||
# modification history
|
||||
# --------------------
|
||||
# 01a,26mar06,c_c created.
|
||||
#
|
||||
# DESCRIPTION
|
||||
# This file contains the makefile rules for building the scopetools libraries
|
||||
#
|
||||
#*/
|
||||
|
||||
TGT_DIR=$(WIND_BASE)/target
|
||||
TOOLS_SRC_ROOT = ../../..
|
||||
|
||||
LIB_BASE_NAME = rtilib
|
||||
EXTRA_DEFINE += -DPtrIntType=long
|
||||
EXTRA_INCLUDE = -I$(TOOLS_SRC_ROOT)/rtilib/include/share \
|
||||
-I$(TOOLS_SRC_ROOT)/rtilib/include/vx
|
||||
DOC_FILES=
|
||||
|
||||
OBJS= connect.o netio_common.o netio_new.o tcp.o dgram.o \
|
||||
netioGlobals.o netioUtils.o
|
||||
|
||||
PKG_H = hostLib.pkg.h netio_common.pkg.h netioGlobals.pkg.h \
|
||||
netioUtils.pkg.h dgram.pkg.h connect.pkg.h
|
||||
|
||||
HDR_PATH = ../../include/share/rtilib
|
||||
HEADERS = $(HDR_PATH)/rti_ip.h $(HDR_PATH)/rti_tcp.h
|
||||
|
||||
include $(TOOLS_SRC_ROOT)/make/common_rules.mk
|
||||
|
||||
# Public header generation (needs to occur after inclusion of rules.library,
|
||||
# otherwise it hides the default build rule).
|
||||
|
||||
$(HDR_PATH)/rti_ip.h : netio_common.c netioGlobals.c netio_new.c netioUtils.c \
|
||||
connect.c
|
||||
$(MAKEHEADER) -C $(MAKEHEADERPUBKEYS) -o $@ $^
|
||||
|
||||
$(HDR_PATH)/rti_tcp.h : tcp.c
|
||||
$(MAKEHEADER) -C $(MAKEHEADERPUBKEYS) -o $@ $^
|
||||
|
||||
# end of rtilib/utils/netio
|
||||
@@ -0,0 +1,385 @@
|
||||
/* connect.c - brief Socket connection utilities */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-2009, 2012-2013 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01c,14oct13,wzc Fix prevent warnings.
|
||||
01b,05jul12,wzc WIND00357415 - Remove building warnings.
|
||||
01a,23jul09,wzc Change copyright notice and module layout.
|
||||
4.2g,14jul03,cc Ported to Integrity
|
||||
4.2c,12dec02,cc Ported to QNX
|
||||
4.1g,08aug01,sst Merged in upgrade to NetOS3
|
||||
4.1g,27jul01,ad split Lynx from UNIX builds
|
||||
4.1f,30may01,eys Ported to CE 3.0
|
||||
4.1f,20may01,sjr Used RtiIsDigit for VxWorks AE since isdigit is not always
|
||||
available in user domains in AE.
|
||||
4.1a,18sep00,hoc Added Rti in front of Netio
|
||||
4.0d,29jun00,sst Added NetOS support
|
||||
4.0c,06apr00,sst Replace (struct sockaddr *) cast with SOCKADDRIN2OS macro
|
||||
4.0c,04apr00,sst Added pSOS support
|
||||
3.9h,14jun99,mlh Converted to NetioPort.
|
||||
Removed ThreadExit.
|
||||
3.9g,09jun99,mlh Added some doc++ comments.
|
||||
3.9f,16may99,mlh Converted from winsock.h to windows.h.
|
||||
3.8c,14oct98,nm Porting to Windows CE: it doesn't have isdigit, use iswdigit.
|
||||
3.8a,20mar98,nm psyserr() is obsolete, use PError() instead.
|
||||
3.7h,22dec97,nm Added RTI_WINCE ifdefs.
|
||||
3.5f,11nov96,gpc Removed SO_REUSEADDR because in OSs taht support IP
|
||||
Multicasting (e.g. Irix 5.3, Solaris 2.5, NT) this
|
||||
allows multiple processes to bid to the same port.
|
||||
3.5a,03jun96,sas Added SO_REUSEADDR.
|
||||
3.5a,24may96,mlh GethostName must handle empty hostname string. It now returns
|
||||
RTI_FALSE whenever someone passed an empty string hostname
|
||||
Added includes to get rid of inet_addr implicit def.
|
||||
3.5a,23may96,gpc IpConnectGetConnection() accepts NULL as an alias for the
|
||||
local host.
|
||||
3.5a,23may96,gpc Punt ConnectIpAddressGet() replaced by NetioAddr object API.
|
||||
3.5a,15may96,mha Port object-based API
|
||||
rti,03apr96,vwc Use RtiNetioErrno instead of errno
|
||||
RTI,11mar96,gpc Added reference to netioUtils for distribution
|
||||
information
|
||||
RTI,20dec95,sda Changed private, public to Private, Public.
|
||||
01c,14jul95,gpc Merged in changes made by Adam to support WinSock/NT.
|
||||
01a,24may94,sas Added AddressInDotNotation support.
|
||||
|
||||
ancient history
|
||||
---------------
|
||||
Written by: Stan Schneider, Real-Time Innovations January, 1991
|
||||
Revised: Stan Schneider, RTI June, 1991
|
||||
|
||||
Modified for use with mangen instead of make_man
|
||||
---------------------------------------------------------------------
|
||||
*/
|
||||
/* $Id: connect.c,v 1.73 2007/08/21 01:00:19 panderse Exp $ */
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
|
||||
Brief Socket connection utilities.
|
||||
*/
|
||||
|
||||
/* These are all symbolically linked to the VxWorks equivalents! */
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#if !defined(RTI_WINCE) && !defined(RTI_WINCE30) && !defined(RTI_PSOS) && !defined(RTI_NETOS)
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#if !defined(RTI_WIN32) && !defined(RTI_WINCE) && !defined(RTI_WINCE30) && !defined(RTI_PSOS) && !defined(RTI_NETOS) && !defined(RTI_OPENVMS)
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#if defined(RTI_UNIX) || defined(RTI_LYNX) || defined(RTI_QNX)
|
||||
#include <arpa/inet.h>
|
||||
#elif defined(RTI_VXWORKS)
|
||||
#include <inetLib.h>
|
||||
#elif defined(RTI_PSOS)
|
||||
#include <pna.h>
|
||||
#include "hostLib.pkg.h"
|
||||
#elif defined(RTI_OPENVMS)
|
||||
#include <types.h>
|
||||
#include <tcp.h> /* for the u_* types */
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <socket.h>
|
||||
#endif
|
||||
|
||||
#if defined(RTI_INTY)
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h> /* for gethostbyaddr etc. */
|
||||
#endif
|
||||
|
||||
#include "rtilib/vxVersions.h"
|
||||
|
||||
#include "rtilib/rti_types.h"
|
||||
#include "netio_common.pkg.h"
|
||||
#include "netioGlobals.pkg.h"
|
||||
#include "netioUtils.pkg.h"
|
||||
#include "rtilib/makeheader.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
@brief Assign a port number to a socket.
|
||||
|
||||
Bind a port to a socket. Fills in sockAddr. If the passed port number is
|
||||
0, then the system will assign a new port number. If the passed port number
|
||||
is in use, RtiConnectBind returns -1. If the bind succeeds, the bound port
|
||||
number is returned, and is also available as ntohs(sockAddr->sin_port).
|
||||
This is only necessary if the socket will receive data.
|
||||
*/
|
||||
Public DllExport
|
||||
int RtiConnectBind(RTINetioSocket sd, struct sockaddr_in *sockAddr,
|
||||
int portnum)
|
||||
{
|
||||
#if defined(RTI_NETOS)
|
||||
int searchContinues = 0;
|
||||
long err = 0;
|
||||
long ipAddr;
|
||||
#endif
|
||||
#if defined(RTI_OPENVMS) || defined(RTI_LINUX)
|
||||
/* TO DO: We should consider using "socklen_t" on other platforms... */
|
||||
socklen_t sockAddrLen = sizeof(struct sockaddr_in);
|
||||
#else
|
||||
int sockAddrLen = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if(!sockAddr || (portnum < 0)) {
|
||||
return RTI_NETIO_PORT_INVALID;
|
||||
}
|
||||
|
||||
memset((char *) sockAddr, 0, sizeof(struct sockaddr_in));
|
||||
sockAddr->sin_family = AF_INET;
|
||||
/* 0=>bind determines the port number */
|
||||
sockAddr->sin_port = (unsigned short)htons(portnum);
|
||||
sockAddr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
#if defined(RTI_NETOS)
|
||||
|
||||
/* Bind our name to the passed socket. */
|
||||
if(t_bind(sd, SOCKADDRIN2OS(sockAddr)) < 0) {
|
||||
err = t_errno(sd);
|
||||
if (err != EADDRINUSE) {
|
||||
RtiN1Warning(RTI_MSG_NETIO_BIND_FAILED,
|
||||
RTI_MSG_NETIO_IN_CONNECTBIND, sd, err);
|
||||
}
|
||||
return RTI_NETIO_PORT_INVALID;
|
||||
}
|
||||
|
||||
/* Find out what port number bind assigned to our socket */
|
||||
if (t_getsockname(sd, SOCKADDRIN2OS(sockAddr)) < 0) {
|
||||
err = t_errno(sd);
|
||||
RtiN0Warning(RTI_MSG_NETIO_GETSOCKNAME_FAILED,
|
||||
RTI_MSG_NETIO_IN_CONNECTBIND, sd, err);
|
||||
return RTI_NETIO_PORT_INVALID;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Bind our name to the passed socket. */
|
||||
if (bind(sd, SOCKADDRIN2OS(sockAddr), sizeof(struct sockaddr_in)) != 0) {
|
||||
if (RtiNetioErrnoGet() != EADDRINUSE) {
|
||||
RtiN1Warning(RTI_MSG_NETIO_BIND_FAILED,
|
||||
RTI_MSG_NETIO_IN_CONNECTBIND, sd, RtiNetioErrnoGet());
|
||||
}
|
||||
return RTI_NETIO_PORT_INVALID;
|
||||
}
|
||||
|
||||
/* Find out what port number bind assigned to our socket */
|
||||
if (getsockname(sd, SOCKADDRIN2OS(sockAddr), &sockAddrLen) < 0) {
|
||||
RtiN0Warning(RTI_MSG_NETIO_GETSOCKNAME_FAILED,
|
||||
RTI_MSG_NETIO_IN_CONNECTBIND, sd, RtiNetioErrnoGet());
|
||||
return RTI_NETIO_PORT_INVALID;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return (ntohs(sockAddr->sin_port));
|
||||
}
|
||||
|
||||
#if VXWORKS_AE_VERSION_1_0_OR_BETTER
|
||||
/*e \ingroup rtiNetio
|
||||
Replicate functionality of isdigit() for VxWorks AE for use in user PD
|
||||
when ctype is not included in a system shared library or prebuilt into
|
||||
the user PD.
|
||||
|
||||
@param c The character to test.
|
||||
|
||||
@return Returns 1 if input is an ASCII digit, otherwise 0.
|
||||
*/
|
||||
int RtiIsDigit(int c)
|
||||
{
|
||||
return 4*(c >= '0' && c <= '9');
|
||||
}
|
||||
#endif
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
Check if address has the form XX.XX.XX.XX.
|
||||
|
||||
@param hostName The name of the node.
|
||||
|
||||
@return Returns RTI_TRUE if the hostName parameter is in dot notation.
|
||||
*/
|
||||
RTIBool AddressInDotNotation(const char *hostName)
|
||||
{
|
||||
char c;
|
||||
int i, dots = 0;
|
||||
size_t len = strlen(hostName);
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
c = hostName[i];
|
||||
if (c == '.') {
|
||||
dots++;
|
||||
} else {
|
||||
#if defined(RTI_VXWORKS)
|
||||
#if VXWORKS_AE_VERSION_1_0_OR_BETTER
|
||||
if (!RtiIsDigit((int)c)) {
|
||||
#else
|
||||
if (!isdigit((int)c)) {
|
||||
#endif
|
||||
#elif !defined(RTI_WINCE) && !defined(RTI_WINCE30)
|
||||
if (!isdigit(c)) {
|
||||
#else
|
||||
if (!iswdigit(c)) {
|
||||
#endif
|
||||
return(RTI_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (dots == 3);
|
||||
}
|
||||
|
||||
/*e \ingroup rtiNetio
|
||||
|
||||
@brief Get the socket address of a specified port.
|
||||
|
||||
Fills in sockAddr to match port portnum on host hostname.
|
||||
This routine does not check to see if such a socket actually exists.
|
||||
If hostname==NULL, uses name of local host.
|
||||
|
||||
@param sockAddr
|
||||
Filled in with the IP address and port from hostName and portnum parameters.
|
||||
|
||||
@param portNum
|
||||
The port number.
|
||||
|
||||
@param hostName
|
||||
The name of the computer. There are three possibilities:
|
||||
- hostName is NULL => use local host
|
||||
- hostName is an IP address => translate it to 4 bytes
|
||||
- otherwise => look up hostname in host-name tables
|
||||
|
||||
@return Returns RTI_FALSE if hostname is not found in host tables.
|
||||
*/
|
||||
Public DllExport RTIBool NativeAddressSet(struct sockaddr_in *sockAddr,
|
||||
const char *hostName, int portnum,
|
||||
const char *warnPre)
|
||||
{
|
||||
#if defined(RTI_NETOS) || defined(RTI_INTY)
|
||||
|
||||
struct hostent *hostEntry;
|
||||
if (!sockAddr || (hostName && (hostName[0] == '\0')) ) {
|
||||
RtiN0Warning(RTI_MSG_NETIO_INVALID_PARAMETERS,
|
||||
RTI_MSG_NETIO_IN_NATIVEADDRESSSET);
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
memset((char *) sockAddr, 0, sizeof(struct sockaddr_in));
|
||||
sockAddr->sin_family = AF_INET;
|
||||
sockAddr->sin_port = htons((unsigned short)portnum);
|
||||
|
||||
if (!hostName || (strcmp(hostName, "localhost") == 0) ) {
|
||||
/* (1) */
|
||||
sockAddr->sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
} else {
|
||||
if (AddressInDotNotation(hostName)) {
|
||||
/* (2) */
|
||||
sockAddr->sin_addr.s_addr = inet_addr(hostName);
|
||||
} else {
|
||||
/* (3) */
|
||||
if ( !(hostEntry = gethostbyname((char*)hostName)) ) {
|
||||
RtiN1Warning(RTI_MSG_NETIO_HOST_NOT_FOUND,
|
||||
RTI_MSG_NETIO_IN_NATIVEADDRESSSET, hostName);
|
||||
return(RTI_FALSE);
|
||||
}
|
||||
memcpy(&sockAddr->sin_addr, hostEntry->h_addr_list[0],
|
||||
hostEntry->h_length);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char thisHostName[10];
|
||||
|
||||
|
||||
#if defined(RTI_UNIX) || defined(RTI_LYNX) || defined(RTI_WIN32) || defined(RTI_WINCE) || defined(RTI_WINCE30) || defined(RTI_QNX) || defined(RTI_OPENVMS)
|
||||
struct hostent *hostEntry;
|
||||
#endif
|
||||
|
||||
/* Accessing hostName[0] without checking if hostName is NULL caused
|
||||
Bug #2991.
|
||||
*/
|
||||
if (!sockAddr || (hostName && (hostName[0] == '\0'))) {
|
||||
return RTI_FALSE;
|
||||
}
|
||||
|
||||
/* NULL hostName ==> localhost */
|
||||
if (!hostName) {
|
||||
snprintf(thisHostName, sizeof(thisHostName), "localhost");
|
||||
hostName = thisHostName;
|
||||
}
|
||||
|
||||
memset((char *) sockAddr, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
sockAddr->sin_family = AF_INET;
|
||||
sockAddr->sin_port = (unsigned short)htons(portnum);
|
||||
|
||||
if (AddressInDotNotation(hostName)) {
|
||||
#if defined(RTI_PSOS) || defined (RTI_VXWORKS)
|
||||
sockAddr->sin_addr.s_addr = inet_addr((char *)hostName);
|
||||
#else
|
||||
sockAddr->sin_addr.s_addr = inet_addr(hostName);
|
||||
#endif
|
||||
return RTI_TRUE;
|
||||
}
|
||||
|
||||
#if defined(RTI_UNIX) || defined(RTI_LYNX) || defined(RTI_WIN32) || defined(RTI_WINCE) || defined(RTI_WINCE30) || defined(RTI_QNX) || defined(RTI_OPENVMS)
|
||||
|
||||
hostEntry = gethostbyname(hostName);
|
||||
if ( hostEntry != NULL ) {
|
||||
memcpy(&sockAddr->sin_addr, hostEntry->h_addr_list[0],
|
||||
hostEntry->h_length);
|
||||
} else {
|
||||
RtiN1Warning(RTI_MSG_NETIO_HOST_NOT_FOUND,
|
||||
RTI_MSG_NETIO_IN_NATIVEADDRESSSET, hostName);
|
||||
return(RTI_FALSE);
|
||||
}
|
||||
|
||||
#elif defined(RTI_VXWORKS)
|
||||
|
||||
if ((sockAddr->sin_addr.s_addr = (in_addr_t)hostGetByName((char *)hostName))==((in_addr_t)ERROR)) {
|
||||
RtiN1Warning(RTI_MSG_NETIO_HOST_NOT_FOUND,
|
||||
RTI_MSG_NETIO_IN_NATIVEADDRESSSET, hostName);
|
||||
return(RTI_FALSE);
|
||||
}
|
||||
|
||||
#elif defined(RTI_PSOS)
|
||||
|
||||
if ((sockAddr->sin_addr.s_addr = hostGetByName((char *)hostName)) == -1) {
|
||||
RtiN1Warning(RTI_MSG_NETIO_HOST_NOT_FOUND,
|
||||
RTI_MSG_NETIO_IN_NATIVEADDRESSSET, hostName);
|
||||
return(RTI_FALSE);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Porting needs to be done"
|
||||
#endif
|
||||
|
||||
#endif /* RTI_NETOS */
|
||||
|
||||
return RTI_TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* connect.pkg.h - built from: connect.c */
|
||||
|
||||
/* Copyright (c) 2001, 2024 Wind River Systems, Inc.
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
#ifndef connect_pkg_h
|
||||
#define connect_pkg_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern DllExport
|
||||
int RtiConnectBind(RTINetioSocket sd, struct sockaddr_in *sockAddr,
|
||||
int portnum);
|
||||
|
||||
extern DllExport RTIBool NativeAddressSet(struct sockaddr_in *sockAddr,
|
||||
const char *hostName, int portnum,
|
||||
const char *warnPre);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* connect_pkg_h */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user