original files of m241

This commit is contained in:
neelimap
2026-07-30 11:19:44 +05:30
parent 170c2b3f3a
commit afc7070c1f
12254 changed files with 7655111 additions and 0 deletions
+442
View File
@@ -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
+73
View File
@@ -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
+171
View File
@@ -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);
}
+101
View File
@@ -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 */
+156
View File
@@ -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");
}
+24
View File
@@ -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);
+113
View File
@@ -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
+409
View File
@@ -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");
}
}
}
}
+93
View File
@@ -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);
}
+103
View File
@@ -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(&regs, (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(&regs, (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(&regs, (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);
}
@@ -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