Compare commits
63 Commits
PSI-3.14.1
...
PSI-3.14
| Author | SHA1 | Date | |
|---|---|---|---|
| fe49fa6db3 | |||
| 77aa003153 | |||
| 3b993e2f54 | |||
| f9f48c5267 | |||
| d9105135cc | |||
| c7f30154f0 | |||
| 2d6e308538 | |||
|
|
07c5ad5d5a | ||
|
|
90f1ac3676 | ||
|
|
4b5d43b699 | ||
|
|
043595ca0a | ||
|
|
2c7dae92bc | ||
|
|
76aa3aab01 | ||
| cc5084018b | |||
|
|
375b74a0c0 | ||
| 9f97b4bce0 | |||
| a68f3d62aa | |||
| a9a975b1e4 | |||
| d94e0097a6 | |||
| c951229511 | |||
| 751059eea2 | |||
| 74bba6ec9d | |||
| b68e80fa15 | |||
| a441443bd0 | |||
| e7a300bf9e | |||
| ed1944c54b | |||
| b62938af2f | |||
| b8419ec17d | |||
| 172f170230 | |||
| 795e1a9368 | |||
| 9a3f7e3c52 | |||
| 7c5c03edb0 | |||
| 2e2b7be9bd | |||
| 12af6fa231 | |||
| d0e83116e6 | |||
| 3276e22c82 | |||
| 8b5225c14f | |||
| 962bf4d2dd | |||
| 8a53c494ff | |||
| f65c39c0d2 | |||
| 26b857a8da | |||
| ee1b68d229 | |||
| cbd4634224 | |||
| 543ac1fb75 | |||
| fc3f1fab6a | |||
|
|
4b4d302ded | ||
| 24ab504920 | |||
| 2db93163c1 | |||
| 2ef70f6d7c | |||
|
|
116c90c2ea | ||
|
|
3f3696fb91 | ||
| 06a330ccf8 | |||
| ccbaf557a0 | |||
| 720cc3e84e | |||
| 6f3e74095c | |||
| 871e5c496e | |||
| 44d4e47ec2 | |||
| 394bf30dbf | |||
| 9b9daa9a7c | |||
|
|
ec3b7c364b | ||
| afcb81927e | |||
| 5fe0429c48 | |||
|
|
b9443f8813 |
11
Makefile
11
Makefile
@@ -25,9 +25,16 @@ config_DEPEND_DIRS = src
|
||||
include $(TOP)/configure/RULES_TOP
|
||||
|
||||
|
||||
ifneq ($(INSTALL_LOCATION),$(TOP))
|
||||
UNINSTALL_DIRS += $(INSTALL_LOCATION)/src
|
||||
copysrc:
|
||||
tar cf - --exclude=CVS --exclude=O.* src | tar xf - -C $(INSTALL_LOCATION)
|
||||
else
|
||||
copysrc:
|
||||
@echo "Not doing anything (INSTALL_LOCATION==TOP)"
|
||||
endif
|
||||
|
||||
tar: install copysrc
|
||||
tar cfjP epics_base-3.14.12.tar.bz2 $(INSTALL_LOCATION) --exclude=*.o
|
||||
tar:
|
||||
tar cfjP epics_base-$(EPICS_VERSION_NUMBER).tar.bz2 --exclude=*.o $(INSTALL_LOCATION)
|
||||
|
||||
.PHONY: copysrc tar
|
||||
|
||||
@@ -54,3 +54,6 @@ EPICS_IOC_LOG_PORT=7004
|
||||
EPICS_CMD_PROTO_PORT=
|
||||
EPICS_AR_PORT=7002
|
||||
|
||||
# libCom
|
||||
# Whether to enable priority inheritance -- must be set to Y[ES]/y[es]/T[RUE]/t[rue]/1
|
||||
EPICS_MUTEX_USE_PRIORITY_INHERITANCE="NO"
|
||||
|
||||
@@ -191,7 +191,7 @@ USE_POSIX_THREAD_PRIORITY_SCHEDULING = YES
|
||||
|
||||
# Site version number, if set will append '-' and this string to the
|
||||
# EPICS version number string that is reported by many tools
|
||||
EPICS_SITE_VERSION := $(shell date +%Y-%m)
|
||||
EPICS_SITE_VERSION=$(shell $(PERL) -MPOSIX -e 'print strftime "%Y-%m-%d_$(shell git describe --tags --dirty)", localtime')
|
||||
|
||||
# For GNU compiler, use pipes rather than temporary files for communication
|
||||
# between the various stages of compilation.
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
# Include definitions common to linux pentium targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-x86_64
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-clang
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
1
configure/os/CONFIG.Common.RHEL8-x86_64
Normal file
1
configure/os/CONFIG.Common.RHEL8-x86_64
Normal file
@@ -0,0 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-x86_64
|
||||
1
configure/os/CONFIG.Common.RHEL8-x86_64-clang
Normal file
1
configure/os/CONFIG.Common.RHEL8-x86_64-clang
Normal file
@@ -0,0 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-clang
|
||||
@@ -1,7 +1,4 @@
|
||||
# Include definitions common to linux pentium targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-x86
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
ARCH_DEP_CFLAGS += -march=i686
|
||||
ARCH_DEP_CXXFLAGS += -fno-strict-aliasing
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
# Include definitions common to linux pentium targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-x86_64
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
ARCH_DEP_CXXFLAGS += -fno-strict-aliasing
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.linux-clang
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.vxWorks-ppc604_long
|
||||
VXWORKS_VERSION = 5.5.1
|
||||
VXWORKS_VERSION = 5.5
|
||||
WIND_BASE = /afs/psi.ch/project/vxworks/Tornado2.2.1
|
||||
|
||||
#there is a problem with our ccppc and optimization
|
||||
|
||||
3
configure/os/CONFIG.Common.V69-ppc32
Normal file
3
configure/os/CONFIG.Common.V69-ppc32
Normal file
@@ -0,0 +1,3 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.vxWorks-ppc32
|
||||
VXWORKS_VERSION = 6.9
|
||||
#export LD_LIBRARY_PATH=$(WIND_BASE)/lmapi-5.0/$(WIND_HOST_TYPE)/lib
|
||||
3
configure/os/CONFIG.Common.V69-ppc604
Normal file
3
configure/os/CONFIG.Common.V69-ppc604
Normal file
@@ -0,0 +1,3 @@
|
||||
include $(CONFIG)/os/CONFIG.Common.vxWorks-ppc604_long
|
||||
VXWORKS_VERSION = 6.9
|
||||
#export LD_LIBRARY_PATH=$(WIND_BASE)/lmapi-5.0/$(WIND_HOST_TYPE)/lib
|
||||
@@ -11,8 +11,6 @@ ELDK=/opt/eldk-4.2
|
||||
GNU_TARGET=ppc_4xxFP
|
||||
GNU_DIR=$(ELDK)/usr
|
||||
|
||||
ARCH_DEP_CFLAGS += -fno-strict-aliasing
|
||||
|
||||
# This cross tool chain is installed in a somehow weired way
|
||||
# Without the following lines it does not work on RHEL7
|
||||
# but it worked on SL6
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
ARCH_CLASS = ppc
|
||||
|
||||
SDK = eldk
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
ARCH_CLASS = ppc
|
||||
|
||||
SDK = eldk
|
||||
|
||||
21
configure/os/CONFIG.Common.eldk53-ppc4xxFP
Normal file
21
configure/os/CONFIG.Common.eldk53-ppc4xxFP
Normal file
@@ -0,0 +1,21 @@
|
||||
# DeltaTau PowerPMAC with ELDK 5.3
|
||||
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
ARCH_CLASS = ppc
|
||||
|
||||
SDK = eldk
|
||||
SDK_DIR = /opt/eldk-5.3
|
||||
SDK_HOST_ARCH = $(GNU_HOST_ARCH)-$(SDK)-$(GNU_HOST_OS)
|
||||
GNU_ARCH = ppc440e-linux
|
||||
SDKTARGETSYSROOT=$(SDK_DIR)/powerpc-4xx/sysroots
|
||||
GNU_DIR = $(SDKTARGETSYSROOT)/$(SDK_HOST_ARCH)/usr
|
||||
GNU_BIN = $(GNU_DIR)/bin/$(GNU_ARCH)
|
||||
GNU_TARGET_INCLUDE_DIR =
|
||||
GNU_TARGET=powerpc-linux
|
||||
|
||||
ARCH_DEP_CPPFLAGS = -m32 -mcpu=440fp -mhard-float
|
||||
ARCH_DEP_CPPFLAGS += --sysroot=$(SDKTARGETSYSROOT)/$(GNU_ARCH)
|
||||
ARCH_DEP_LDFLAGS = --sysroot=$(SDKTARGETSYSROOT)/$(GNU_ARCH)
|
||||
AS=$(GNU_BIN)/$(GNU_TARGET)-as
|
||||
@@ -1,10 +1,8 @@
|
||||
# IOxOS IFC1211 with Freescale QorIQ 2.0 toolchain
|
||||
# IOxOS IFC1211 and IFC14xx with Freescale QorIQ 2.0 toolchain
|
||||
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
ARCH_CLASS = ppc
|
||||
|
||||
SDK = fslsdk
|
||||
|
||||
@@ -42,3 +42,5 @@ LDLIBS_READLINE_CURSES = -lreadline -lcurses
|
||||
# Allow site overrides
|
||||
-include $(CONFIG)/os/CONFIG_SITE.Common.linuxCommon
|
||||
-include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).linuxCommon
|
||||
|
||||
CODE_CPPFLAGS += -fno-strict-aliasing
|
||||
|
||||
@@ -14,4 +14,3 @@ COMMANDLINE_LIBRARY = READLINE_NCURSES
|
||||
ARCH_DEP_CXXFLAGS += -Wno-psabi
|
||||
|
||||
ARCH_DEP_CFLAGS += -funwind-tables
|
||||
ARCH_DEP_CXXFLAGS += -fno-strict-aliasing
|
||||
|
||||
@@ -10,4 +10,3 @@ ARCH_CLASS = xscale
|
||||
GNU_DIR=/afs/psi.ch/project/embeddedlinux/moxa/xscale_be/armv5teb-montavista-linuxeabi
|
||||
|
||||
ARCH_DEP_CFLAGS += -funwind-tables
|
||||
ARCH_DEP_CPPFLAGS += -fno-strict-aliasing
|
||||
|
||||
18
configure/os/CONFIG.Common.nilrt7-armv7a
Normal file
18
configure/os/CONFIG.Common.nilrt7-armv7a
Normal file
@@ -0,0 +1,18 @@
|
||||
# National Instruments CompactRIO running LabView RT 19.5.1
|
||||
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
ARCH_CLASS = arm
|
||||
|
||||
GNU_TARGET = arm-linux-gnu
|
||||
|
||||
SYSROOT = /opt/LabVIEW-RT-19.5.1/arm/sysroots/armv7a-vfp-neon-nilrt-linux-gnueabi
|
||||
|
||||
ARCH_DEP_CPPFLAGS += -march=armv7-a -mthumb-interwork -mfloat-abi=softfp -mfpu=neon
|
||||
ARCH_DEP_CPPFLAGS += --sysroot=$(SYSROOT)
|
||||
ARCH_DEP_CPPFLAGS += -I$(SYSROOT)/usr/include/c++/4.7.2/arm-nilrt-linux-gnueabi/
|
||||
ARCH_DEP_CPPFLAGS += -I$(SYSROOT)/usr/include/c++/4.7.2/
|
||||
ARCH_DEP_LDFLAGS += --sysroot=$(SYSROOT)
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE_NCURSES
|
||||
41
configure/os/CONFIG.Common.raspbian-arm
Normal file
41
configure/os/CONFIG.Common.raspbian-arm
Normal file
@@ -0,0 +1,41 @@
|
||||
# RaspberryPi with github.com/raspberrypi/tools toolchain
|
||||
# Tested on:
|
||||
# * Raspberry 3B+ Raspbian 9
|
||||
# * Raspberry 2 Raspbian 7
|
||||
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
# Using readline:
|
||||
# Due to missing/messed up libs in the toolchain, readline needs copies of
|
||||
# libtinfo.so.5.9 and libreadline.so.6.2 from a Raspbian 7 rootfs
|
||||
# /lib/arm-linux-gnueabihf/ to the toolchain, e.g.
|
||||
# $(SDK_DIR)/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf/
|
||||
# and manually created links libtinfo.so.5 and libreadline.so.
|
||||
# For gcc-linaro-arm-linux-gnueabihf-raspbian, an existing incompatible
|
||||
# libtinfo.so.5 is in the way. Remove it.
|
||||
# (Built with glibc 2.16 like installed on Raspbian 9 but toolchain uses glibc 2.13.)
|
||||
# Also copy /usr/include/readline/ directory from some readline 6 installation
|
||||
# to $(SDK_DIR)/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/usr/include/
|
||||
|
||||
ARCH_CLASS = arm
|
||||
|
||||
SDK_DIR = /opt/raspberrypi/arm-bcm2708
|
||||
|
||||
# Available SDK_TARGETs:
|
||||
|
||||
# gcc 4.8.3 for 32 bit hosts with GLIBC 2.3 or higher
|
||||
SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian
|
||||
|
||||
# gcc 4.8.3 for 64 bit hosts with GLIBC 2.14 or higher
|
||||
# SDK_TARGET = gcc-linaro-arm-linux-gnueabihf-raspbian-x64
|
||||
|
||||
# gcc 4.7.1 for 64 bit hosts with GLIBC 2.8 or higher
|
||||
# SDK_TARGET = arm-linux-gnueabihf
|
||||
|
||||
# gcc 4.7.1 for 32 bit hosts with GLIBC 2.4 or higher
|
||||
# SDK_TARGET = arm-bcm2708hardfp-linux-gnueabi
|
||||
# SDK_TARGET = arm-bcm2708-linux-gnueabi
|
||||
|
||||
GNU_DIR = $(SDK_DIR)/$(SDK_TARGET)
|
||||
GNU_TARGET = $(if $(filter arm-bcm2708%,SDK_TARGET),$(SDK_TARGET),arm-linux-gnueabihf)
|
||||
@@ -14,9 +14,11 @@ ARCH_CLASS = ppc
|
||||
|
||||
# Architecture specific build flags
|
||||
ARCH_DEP_CPPFLAGS = -DCPU=PPC604
|
||||
ARCH_DEP_CFLAGS_2 = -mcpu=604 -mstrict-align -mno-implicit-fp
|
||||
ARCH_DEP_CFLAGS_3 = -mcpu=604 -mstrict-align -mno-implicit-fp
|
||||
ARCH_DEP_CFLAGS_4 = -mcpu=604 -mstrict-align -fno-implicit-fp
|
||||
ARCH_DEP_CFLAGS = $(ARCH_DEP_CFLAGS_$(VX_GNU_MAJOR_VERSION))
|
||||
ARCH_DEP_CFLAGS = -mcpu=604 -mstrict-align
|
||||
|
||||
CODE_CFLAGS_2 = -mno-implicit-fp
|
||||
CODE_CFLAGS_3 = -mno-implicit-fp
|
||||
CODE_CFLAGS_4 = -fno-implicit-fp
|
||||
CODE_CFLAGS += $(CODE_CFLAGS_$(VX_GNU_MAJOR_VERSION))
|
||||
|
||||
GNU_TARGET = powerpc-wrs-vxworks
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
# Include definitions common to all Linux targets
|
||||
include $(CONFIG)/os/CONFIG.Common.linuxCommon
|
||||
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
|
||||
ARCH_CLASS = arm64
|
||||
|
||||
SDK = petalinux
|
||||
SDK_DIR = /opt/petalinux-gfa/2017.2
|
||||
SDK_DIR = /opt/petalinux-gfa/2018.1
|
||||
SDK_HOST_ARCH = $(GNU_HOST_ARCH_64)-$(SDK)-$(GNU_HOST_OS)
|
||||
SDK_TARGET = aarch64-xilinx-linux
|
||||
GNU_TARGET = $(SDK_TARGET)
|
||||
|
||||
21
configure/os/CONFIG.Cross_64.RHEL7-x86_64
Normal file
21
configure/os/CONFIG.Cross_64.RHEL7-x86_64
Normal file
@@ -0,0 +1,21 @@
|
||||
# "cross compile" for RHEL7-x86_64 on other 64 bit Linux version
|
||||
# Expects RHEL7 RPMs c++ and readline-devel installed in $(SYSROOT)
|
||||
# This can be installed on RHEL7 with:
|
||||
# yum install --installroot=$(SYSROOT) <packages>
|
||||
# (Assuming $(SYSROOT) is on a shared network volume.)
|
||||
# Optionally use a newer toolset (installed on $(SYSROOT)).
|
||||
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
|
||||
|
||||
SYSROOT = /opt/RHEL7
|
||||
TOOLSET_LOCATION = /opt/rh
|
||||
|
||||
# Do NOT set GNU_BIN (or else ...)!
|
||||
TOOLSET_DIR = $(TOOLSET:%=$(TOOLSET_LOCATION)/%/root)
|
||||
CC = $(SYSROOT)$(TOOLSET_DIR)/bin/gcc
|
||||
CCC = $(SYSROOT)$(TOOLSET_DIR)/bin/g++
|
||||
# Set LD_LIBRARY_PATH and BFLAG only with TOOLSET
|
||||
LD_LIBRARY_PATH = $(if $(TOOLSET),$(SYSROOT)$(TOOLSET_DIR)/lib64)
|
||||
BFLAG = $(if $(TOOLSET),-B$(SYSROOT)$(TOOLSET_DIR)/bin)
|
||||
TARGET_CPPFLAGS += --sysroot=$(SYSROOT) $(BFLAG)
|
||||
TARGET_LDFLAGS += --sysroot=$(SYSROOT) $(BFLAG)
|
||||
1
configure/os/CONFIG.RHEL8-x86_64.Common
Normal file
1
configure/os/CONFIG.RHEL8-x86_64.Common
Normal file
@@ -0,0 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.linux-x86_64.Common
|
||||
1
configure/os/CONFIG.RHEL8-x86_64.RHEL7-x86_64
Normal file
1
configure/os/CONFIG.RHEL8-x86_64.RHEL7-x86_64
Normal file
@@ -0,0 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.Cross_64.RHEL7-x86_64
|
||||
1
configure/os/CONFIG.RHEL8-x86_64.RHEL8-x86_64
Normal file
1
configure/os/CONFIG.RHEL8-x86_64.RHEL8-x86_64
Normal file
@@ -0,0 +1 @@
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86
|
||||
1
configure/os/CONFIG.RHEL8-x86_64.nilrt7-armv7a
Normal file
1
configure/os/CONFIG.RHEL8-x86_64.nilrt7-armv7a
Normal file
@@ -0,0 +1 @@
|
||||
GNU_BIN=/opt/RHEL7/bin
|
||||
@@ -1,2 +1,3 @@
|
||||
#CONFIG.$(EPICS_HOST_ARCH).Common is required by build system
|
||||
#Include definitions common to linux hosts
|
||||
include $(CONFIG)/os/CONFIG.linux-x86.Common
|
||||
|
||||
@@ -85,16 +85,20 @@ CPP = cl -nologo -C -E
|
||||
|
||||
# Configure OS vendor C++ compiler
|
||||
#
|
||||
# __STDC__=0 gives us both:
|
||||
# 1) define STDC for code (pretend ANSI conformance)
|
||||
# 2) set it to 0 to use MS C "extensions" (open for _open etc.)
|
||||
# because MS uses: if __STDC__ ... disable many nice things
|
||||
#
|
||||
# -EHsc - generate code for exceptions
|
||||
# -GR - generate code for run time type identification
|
||||
#
|
||||
CCC = cl -EHsc -GR
|
||||
CODE_CPPFLAGS += -nologo -D__STDC__=0
|
||||
|
||||
# Other compiler flags, used for CPP, C and C++
|
||||
#
|
||||
# -FC - Show absolute path of source file in diagnostics
|
||||
# -D__STDC__=0 gives us both:
|
||||
# 1) define STDC for code (pretend ANSI conformance)
|
||||
# 2) set it to 0 to use MS C "extensions" (open for _open etc.)
|
||||
# because MS uses: if __STDC__ ... disable many nice things
|
||||
#
|
||||
CODE_CPPFLAGS += -nologo -FC -D__STDC__=0
|
||||
CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
|
||||
|
||||
|
||||
|
||||
4
configure/os/CONFIG_SITE.Common.linuxCommon
Normal file
4
configure/os/CONFIG_SITE.Common.linuxCommon
Normal file
@@ -0,0 +1,4 @@
|
||||
COMMANDLINE_LIBRARY = READLINE
|
||||
ifeq ($(filter SL% RHEL%,$(T_A)),)
|
||||
VALID_BUILDS = Ioc
|
||||
endif
|
||||
@@ -8,6 +8,13 @@ CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64-clang
|
||||
CROSS_COMPILER_TARGET_ARCHS += SL6-x86_64
|
||||
|
||||
# Build for old SL6 32 bit
|
||||
CROSS_COMPILER_TARGET_ARCHS += SL6-x86
|
||||
#CROSS_COMPILER_TARGET_ARCHS += SL6-x86
|
||||
|
||||
# Zynq
|
||||
CROSS_COMPILER_TARGET_ARCHS += yocto21-aarch64
|
||||
|
||||
# NI Linux Real-Time 7.x
|
||||
# requires RPM gcc-c++-arm-linux-gnu
|
||||
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a
|
||||
|
||||
include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
|
||||
|
||||
15
configure/os/CONFIG_SITE.RHEL8-x86_64.Common
Normal file
15
configure/os/CONFIG_SITE.RHEL8-x86_64.Common
Normal file
@@ -0,0 +1,15 @@
|
||||
include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
|
||||
|
||||
# Improved error checking with clang
|
||||
# Does not compile with clang 13!
|
||||
#CROSS_COMPILER_TARGET_ARCHS += RHEL8-x86_64-clang
|
||||
|
||||
# Build for old RHEL7 64 bit
|
||||
CROSS_COMPILER_TARGET_ARCHS += RHEL7-x86_64
|
||||
|
||||
# Zynq
|
||||
CROSS_COMPILER_TARGET_ARCHS += yocto21-aarch64
|
||||
|
||||
# NI Linux Real-Time 7.x
|
||||
# requires RPM gcc-c++-arm-linux-gnu
|
||||
CROSS_COMPILER_TARGET_ARCHS += nilrt7-armv7a
|
||||
@@ -2,6 +2,6 @@
|
||||
CROSS_COMPILER_TARGET_ARCHS += SL6-x86
|
||||
|
||||
# Improved error checking with clang
|
||||
CROSS_COMPILER_TARGET_ARCHS += SL6-x86_64-clang
|
||||
#CROSS_COMPILER_TARGET_ARCHS += SL6-x86_64-clang
|
||||
|
||||
include $(CONFIG)/os/CONFIG_SITE.linux-x86_64.Common
|
||||
|
||||
@@ -3,19 +3,21 @@
|
||||
# Site override definitions for linux-x86 host builds
|
||||
#-------------------------------------------------------
|
||||
|
||||
# JBA test override values
|
||||
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040 solaris-sparc
|
||||
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040
|
||||
#CROSS_COMPILER_TARGET_ARCHS = RTEMS-mvme2100 RTEMS-pc386 # RTEMS-mvme5500 RTEMS-mvme167
|
||||
|
||||
GNU_HOST_ARCH=i686
|
||||
GNU_HOST_OS=linux
|
||||
|
||||
# vxWorks 5 for MVxxxx boards
|
||||
# LD_LIBRARY_PATH may cause problems for eldk53-ppc4xxFP
|
||||
LD_LIBRARY_PATH=
|
||||
|
||||
# vxWorks 5.5 for MVxxxx boards
|
||||
CROSS_COMPILER_TARGET_ARCHS += T2-ppc604
|
||||
|
||||
# vxWorks 6.7 for MVxxxx boards
|
||||
CROSS_COMPILER_TARGET_ARCHS += V67-ppc604
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V67-ppc604
|
||||
|
||||
# vxWorks 6.9 for MVxxxx boards
|
||||
CROSS_COMPILER_TARGET_ARCHS += V69-ppc604
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V69-ppc32
|
||||
|
||||
# NI compact RIO
|
||||
CROSS_COMPILER_TARGET_ARCHS += V63-ppc603
|
||||
@@ -34,9 +36,13 @@ CROSS_COMPILER_TARGET_ARCHS += eldk52-e500v2
|
||||
|
||||
# DeltaTau PowerPMAC
|
||||
CROSS_COMPILER_TARGET_ARCHS += eldk42-ppc4xxFP
|
||||
CROSS_COMPILER_TARGET_ARCHS += eldk53-ppc4xxFP
|
||||
|
||||
# Test other vxWorks versions
|
||||
CROSS_COMPILER_TARGET_ARCHS += V66-ppc603
|
||||
CROSS_COMPILER_TARGET_ARCHS += V66-ppc604
|
||||
CROSS_COMPILER_TARGET_ARCHS += V63-ppc604
|
||||
CROSS_COMPILER_TARGET_ARCHS += V62-ppc604
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V66-ppc603
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V66-ppc604
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V63-ppc604
|
||||
#CROSS_COMPILER_TARGET_ARCHS += V62-ppc604
|
||||
|
||||
# Raspberry Pi
|
||||
CROSS_COMPILER_TARGET_ARCHS += raspbian-arm
|
||||
|
||||
@@ -13,6 +13,3 @@ GNU_HOST_ARCH_64=x86_64
|
||||
|
||||
# IOxOS IFC1211
|
||||
CROSS_COMPILER_TARGET_ARCHS += fslqoriq20-e6500_64
|
||||
|
||||
# Zynq
|
||||
CROSS_COMPILER_TARGET_ARCHS += yocto21-aarch64
|
||||
|
||||
@@ -33,6 +33,7 @@ INC += dbIocRegister.h
|
||||
# The following go away what old database access goes away
|
||||
INC += db_access_routines.h
|
||||
INC += db_convert.h
|
||||
INC += dbCaPvt.h
|
||||
|
||||
DBDINC += menuAlarmSevr
|
||||
DBDINC += menuAlarmStat
|
||||
|
||||
@@ -110,9 +110,7 @@ static void callbackShutdown(void *arg)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) {
|
||||
int lockKey = epicsInterruptLock();
|
||||
int ok = epicsRingPointerPush(callbackQ[i], &exitCallback);
|
||||
epicsInterruptUnlock(lockKey);
|
||||
epicsEventSignal(callbackSem[i]);
|
||||
if (ok) epicsEventWait(startStopEvent);
|
||||
}
|
||||
@@ -128,7 +126,7 @@ static void callbackInitOnce(void *arg)
|
||||
epicsThreadId tid;
|
||||
|
||||
callbackSem[i] = epicsEventMustCreate(epicsEventEmpty);
|
||||
callbackQ[i] = epicsRingPointerCreate(callbackQueueSize);
|
||||
callbackQ[i] = epicsRingPointerLockedCreate(callbackQueueSize);
|
||||
if (callbackQ[i] == 0)
|
||||
cantProceed("epicsRingPointerCreate failed for %s\n",
|
||||
threadName[i]);
|
||||
@@ -154,7 +152,6 @@ void callbackRequest(CALLBACK *pcallback)
|
||||
{
|
||||
int priority;
|
||||
int pushOK;
|
||||
int lockKey;
|
||||
|
||||
if (!pcallback) {
|
||||
epicsInterruptContextMessage("callbackRequest: pcallback was NULL\n");
|
||||
@@ -167,9 +164,7 @@ void callbackRequest(CALLBACK *pcallback)
|
||||
}
|
||||
if (ringOverflow[priority]) return;
|
||||
|
||||
lockKey = epicsInterruptLock();
|
||||
pushOK = epicsRingPointerPush(callbackQ[priority], pcallback);
|
||||
epicsInterruptUnlock(lockKey);
|
||||
|
||||
if (!pushOK) {
|
||||
epicsInterruptContextMessage(fullMessage[priority]);
|
||||
|
||||
@@ -90,7 +90,8 @@ struct event_user {
|
||||
epicsMutexId lock;
|
||||
epicsEventId ppendsem; /* Wait while empty */
|
||||
epicsEventId pflush_sem; /* wait for flush */
|
||||
|
||||
epicsEventId pexitsem; /* wait for event task to join */
|
||||
|
||||
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
|
||||
void *extralabor_arg;/* parameter to above */
|
||||
|
||||
@@ -293,36 +294,45 @@ dbEventCtx epicsShareAPI db_init_events (void)
|
||||
if (!evUser) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Flag will be cleared when event task starts */
|
||||
evUser->pendexit = TRUE;
|
||||
|
||||
evUser->firstque.evUser = evUser;
|
||||
evUser->firstque.writelock = epicsMutexCreate();
|
||||
if (!evUser->firstque.writelock) {
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->firstque.writelock)
|
||||
goto fail;
|
||||
|
||||
evUser->ppendsem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->ppendsem) {
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->ppendsem)
|
||||
goto fail;
|
||||
evUser->pflush_sem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->pflush_sem) {
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->pflush_sem)
|
||||
goto fail;
|
||||
evUser->lock = epicsMutexCreate();
|
||||
if (!evUser->lock) {
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
epicsEventDestroy (evUser->pflush_sem);
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
return NULL;
|
||||
}
|
||||
if (!evUser->lock)
|
||||
goto fail;
|
||||
evUser->pexitsem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->pexitsem)
|
||||
goto fail;
|
||||
|
||||
evUser->flowCtrlMode = FALSE;
|
||||
evUser->extraLaborBusy = FALSE;
|
||||
evUser->pSuicideEvent = NULL;
|
||||
return (dbEventCtx) evUser;
|
||||
fail:
|
||||
if(evUser->lock)
|
||||
epicsMutexDestroy (evUser->lock);
|
||||
if(evUser->firstque.writelock)
|
||||
epicsMutexDestroy (evUser->firstque.writelock);
|
||||
if(evUser->ppendsem)
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
if(evUser->pflush_sem)
|
||||
epicsEventDestroy (evUser->pflush_sem);
|
||||
if(evUser->pexitsem)
|
||||
epicsEventDestroy (evUser->pexitsem);
|
||||
freeListFree(dbevEventUserFreeList,evUser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -346,10 +356,26 @@ void epicsShareAPI db_close_events (dbEventCtx ctx)
|
||||
* hazardous to the system's health.
|
||||
*/
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->pendexit = TRUE;
|
||||
if(!evUser->pendexit) { /* event task running */
|
||||
evUser->pendexit = TRUE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
/* wait for task to exit */
|
||||
epicsEventMustWait(evUser->pexitsem);
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
|
||||
epicsEventDestroy(evUser->pexitsem);
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -964,6 +990,7 @@ static void event_task (void *pParm)
|
||||
} while( ! pendexit );
|
||||
|
||||
epicsMutexDestroy(evUser->firstque.writelock);
|
||||
evUser->firstque.writelock = (epicsMutexId)0xdeadbeef;
|
||||
|
||||
{
|
||||
struct event_que *nextque;
|
||||
@@ -972,19 +999,16 @@ static void event_task (void *pParm)
|
||||
while(ev_que){
|
||||
nextque = ev_que->nextque;
|
||||
epicsMutexDestroy(ev_que->writelock);
|
||||
ev_que->writelock = (epicsMutexId)0xdeadbeef;
|
||||
freeListFree(dbevEventQueueFreeList, ev_que);
|
||||
ev_que = nextque;
|
||||
}
|
||||
}
|
||||
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
|
||||
taskwdRemove(epicsThreadGetIdSelf());
|
||||
|
||||
epicsEventSignal(evUser->pexitsem);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1008,7 +1032,6 @@ int epicsShareAPI db_start_events (
|
||||
return DB_EVENT_OK;
|
||||
}
|
||||
|
||||
evUser->pendexit = FALSE;
|
||||
evUser->init_func = init_func;
|
||||
evUser->init_func_arg = init_func_arg;
|
||||
if (!taskname) {
|
||||
@@ -1022,6 +1045,7 @@ int epicsShareAPI db_start_events (
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
return DB_EVENT_ERROR;
|
||||
}
|
||||
evUser->pendexit = FALSE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
return DB_EVENT_OK;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ epicsExportAddress(int,dbRecordsOnceOnly);
|
||||
epicsShareDef int dbBptNotMonotonic=0;
|
||||
epicsExportAddress(int,dbBptNotMonotonic);
|
||||
|
||||
epicsShareDef int dbQuietMacroWarnings=0;
|
||||
epicsExportAddress(int,dbQuietMacroWarnings);
|
||||
|
||||
/*private routines */
|
||||
static void yyerrorAbort(char *str);
|
||||
static void allocTemp(void *pvoid);
|
||||
@@ -227,6 +230,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
free((void *)macPairs);
|
||||
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
}
|
||||
macSuppressWarning(macHandle,dbQuietMacroWarnings);
|
||||
}
|
||||
pinputFile = dbCalloc(1,sizeof(inputFile));
|
||||
if (filename) {
|
||||
@@ -960,23 +964,29 @@ static void dbRecordHead(char *recordType, char *name, int visible)
|
||||
|
||||
static void dbRecordField(char *name,char *value)
|
||||
{
|
||||
DBENTRY *pdbentry;
|
||||
tempListNode *ptempListNode;
|
||||
long status;
|
||||
DBENTRY *pdbentry;
|
||||
tempListNode *ptempListNode;
|
||||
long status;
|
||||
|
||||
if(duplicate) return;
|
||||
if (duplicate) return;
|
||||
ptempListNode = (tempListNode *)ellFirst(&tempList);
|
||||
pdbentry = ptempListNode->item;
|
||||
status = dbFindField(pdbentry,name);
|
||||
if(status) {
|
||||
epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
|
||||
dbGetRecordName(pdbentry), name);
|
||||
yyerror(NULL);
|
||||
return;
|
||||
if (status) {
|
||||
epicsPrintf("Record \"%s\" does not have a field \"%s\"\n",
|
||||
dbGetRecordName(pdbentry), name);
|
||||
yyerror(NULL);
|
||||
return;
|
||||
}
|
||||
if (pdbentry->indfield == 0) {
|
||||
epicsPrintf("Can't set \"NAME\" field of record \"%s\"\n",
|
||||
dbGetRecordName(pdbentry));
|
||||
yyerror(NULL);
|
||||
return;
|
||||
}
|
||||
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
|
||||
status = dbPutString(pdbentry,value);
|
||||
if(status) {
|
||||
if (status) {
|
||||
epicsPrintf("Can't set \"%s.%s\" to \"%s\"\n",
|
||||
dbGetRecordName(pdbentry), name, value);
|
||||
yyerror(NULL);
|
||||
@@ -986,33 +996,33 @@ static void dbRecordField(char *name,char *value)
|
||||
|
||||
static void dbRecordInfo(char *name, char *value)
|
||||
{
|
||||
DBENTRY *pdbentry;
|
||||
tempListNode *ptempListNode;
|
||||
long status;
|
||||
DBENTRY *pdbentry;
|
||||
tempListNode *ptempListNode;
|
||||
long status;
|
||||
|
||||
if(duplicate) return;
|
||||
if (duplicate) return;
|
||||
ptempListNode = (tempListNode *)ellFirst(&tempList);
|
||||
pdbentry = ptempListNode->item;
|
||||
status = dbPutInfo(pdbentry,name,value);
|
||||
if(status) {
|
||||
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
|
||||
if (status) {
|
||||
epicsPrintf("Can't set \"%s\" info \"%s\" to \"%s\"\n",
|
||||
dbGetRecordName(pdbentry), name, value);
|
||||
yyerror(NULL);
|
||||
return;
|
||||
yyerror(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void dbRecordAlias(char *name)
|
||||
{
|
||||
DBENTRY *pdbentry;
|
||||
tempListNode *ptempListNode;
|
||||
long status;
|
||||
DBENTRY *pdbentry;
|
||||
tempListNode *ptempListNode;
|
||||
long status;
|
||||
|
||||
if(duplicate) return;
|
||||
if (duplicate) return;
|
||||
ptempListNode = (tempListNode *)ellFirst(&tempList);
|
||||
pdbentry = ptempListNode->item;
|
||||
status = dbCreateAlias(pdbentry, name);
|
||||
if(status) {
|
||||
if (status) {
|
||||
epicsPrintf("Can't create alias \"%s\" for \"%s\"\n",
|
||||
name, dbGetRecordName(pdbentry));
|
||||
yyerror(NULL);
|
||||
@@ -1022,15 +1032,16 @@ static void dbRecordAlias(char *name)
|
||||
|
||||
static void dbAlias(char *name, char *alias)
|
||||
{
|
||||
DBENTRY dbEntry;
|
||||
DBENTRY *pdbEntry = &dbEntry;
|
||||
DBENTRY dbEntry;
|
||||
DBENTRY *pdbEntry = &dbEntry;
|
||||
|
||||
dbInitEntry(pdbbase, pdbEntry);
|
||||
if (dbFindRecord(pdbEntry, name)) {
|
||||
epicsPrintf("Alias \"%s\" refers to unknown record \"%s\"\n",
|
||||
alias, name);
|
||||
yyerror(NULL);
|
||||
} else if (dbCreateAlias(pdbEntry, alias)) {
|
||||
}
|
||||
else if (dbCreateAlias(pdbEntry, alias)) {
|
||||
epicsPrintf("Can't create alias \"%s\" referring to \"%s\"\n",
|
||||
alias, name);
|
||||
yyerror(NULL);
|
||||
@@ -1040,14 +1051,14 @@ static void dbAlias(char *name, char *alias)
|
||||
|
||||
static void dbRecordBody(void)
|
||||
{
|
||||
DBENTRY *pdbentry;
|
||||
DBENTRY *pdbentry;
|
||||
|
||||
if(duplicate) {
|
||||
duplicate = FALSE;
|
||||
return;
|
||||
if (duplicate) {
|
||||
duplicate = FALSE;
|
||||
return;
|
||||
}
|
||||
pdbentry = (DBENTRY *)popFirstTemp();
|
||||
if(ellCount(&tempList))
|
||||
yyerrorAbort("dbRecordBody: tempList not empty");
|
||||
if (ellCount(&tempList))
|
||||
yyerrorAbort("dbRecordBody: tempList not empty");
|
||||
dbFreeEntry(pdbentry);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ epicsReadline_INCLUDES += $(INCLUDES_$(COMMANDLINE_LIBRARY))
|
||||
|
||||
#POSIX thread priority scheduling flag
|
||||
THREAD_CPPFLAGS_NO += -DDONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
osdMutex_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
|
||||
osdThread_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
|
||||
osdSpin_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING))
|
||||
|
||||
#epicsVersion is created by this Makefile
|
||||
INC += epicsVersion.h
|
||||
@@ -160,6 +162,7 @@ INC += osdInterrupt.h
|
||||
|
||||
INC += epicsMutex.h
|
||||
INC += osdMutex.h
|
||||
INC += epicsSpin.h
|
||||
INC += epicsEvent.h
|
||||
INC += osdEvent.h
|
||||
INC += epicsMath.h
|
||||
@@ -224,6 +227,7 @@ SRCS += osdStdio.c
|
||||
|
||||
SRCS += osdThread.c
|
||||
SRCS += osdMutex.c
|
||||
SRCS += osdSpin.c
|
||||
SRCS += osdEvent.c
|
||||
SRCS += osdTime.cpp
|
||||
SRCS += osdProcess.c
|
||||
|
||||
1
src/libCom/env/envDefs.h
vendored
1
src/libCom/env/envDefs.h
vendored
@@ -69,6 +69,7 @@ epicsShareExtern const ENV_PARAM EPICS_CMD_PROTO_PORT;
|
||||
epicsShareExtern const ENV_PARAM EPICS_AR_PORT;
|
||||
epicsShareExtern const ENV_PARAM IOCSH_PS1;
|
||||
epicsShareExtern const ENV_PARAM IOCSH_HISTSIZE;
|
||||
epicsShareExtern const ENV_PARAM EPICS_MUTEX_USE_PRIORITY_INHERITANCE;
|
||||
|
||||
epicsShareExtern const ENV_PARAM *env_param_list[];
|
||||
|
||||
|
||||
@@ -51,9 +51,8 @@ typedef struct errnumnode {
|
||||
#define NHASH 256
|
||||
|
||||
|
||||
static ELLLIST errnumlist = ELLLIST_INIT;
|
||||
static ERRNUMNODE **hashtable;
|
||||
static int initialized = FALSE;
|
||||
static ERRNUMNODE **hashtable = NULL;
|
||||
#define initialized (hashtable!=NULL)
|
||||
extern ERRSYMTAB_ID errSymTbl;
|
||||
|
||||
/****************************************************************
|
||||
@@ -67,12 +66,8 @@ extern ERRSYMTAB_ID errSymTbl;
|
||||
int epicsShareAPI errSymBld(void)
|
||||
{
|
||||
ERRSYMBOL *errArray = errSymTbl->symbols;
|
||||
ERRNUMNODE *perrNumNode = NULL;
|
||||
ERRNUMNODE *pNextNode = NULL;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
int i;
|
||||
int modnum;
|
||||
unsigned short hashInd;
|
||||
|
||||
if(initialized) return(0);
|
||||
hashtable = (ERRNUMNODE**)callocMustSucceed
|
||||
@@ -89,21 +84,6 @@ int epicsShareAPI errSymBld(void)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
perrNumNode = (ERRNUMNODE *) ellFirst(&errnumlist);
|
||||
while (perrNumNode) {
|
||||
/* hash each perrNumNode->errNum */
|
||||
hashInd = errhash(perrNumNode->errNum);
|
||||
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
|
||||
pNextNode = (ERRNUMNODE*) *phashnode;
|
||||
/* search for last node (NULL) of hashnode linked list */
|
||||
while (pNextNode) {
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
*phashnode = perrNumNode;
|
||||
perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode);
|
||||
}
|
||||
initialized = TRUE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -125,16 +105,33 @@ unsigned short errnum;
|
||||
|
||||
/****************************************************************
|
||||
* ERRSYMBOLADD
|
||||
* adds symbols to the master errnumlist as compiled from errSymTbl.c
|
||||
* adds symbols to the master hashtable as compiled from errSymTbl.c
|
||||
***************************************************************/
|
||||
int epicsShareAPI errSymbolAdd (long errNum,char *name)
|
||||
{
|
||||
ERRNUMNODE *pNew;
|
||||
ERRNUMNODE *perrNumNode;
|
||||
ERRNUMNODE *pNextNode = NULL;
|
||||
ERRNUMNODE **phashnode = NULL;
|
||||
unsigned short hashInd;
|
||||
|
||||
if(!initialized) errSymBld();
|
||||
|
||||
perrNumNode = (ERRNUMNODE*)callocMustSucceed(1,sizeof(ERRNUMNODE),"errSymbolAdd");
|
||||
perrNumNode->errNum = errNum;
|
||||
perrNumNode->message = name;
|
||||
|
||||
/* hash each perrNumNode->errNum */
|
||||
hashInd = errhash(perrNumNode->errNum);
|
||||
phashnode = (ERRNUMNODE**)&hashtable[hashInd];
|
||||
pNextNode = (ERRNUMNODE*) *phashnode;
|
||||
/* search for last node (NULL) of hashnode linked list */
|
||||
while (pNextNode) {
|
||||
phashnode = &pNextNode->hashnode;
|
||||
pNextNode = *phashnode;
|
||||
}
|
||||
*phashnode = perrNumNode;
|
||||
perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode);
|
||||
|
||||
pNew = (ERRNUMNODE*)callocMustSucceed(1,sizeof(ERRNUMNODE),"errSymbolAdd");
|
||||
pNew->errNum = errNum;
|
||||
pNew->message = name;
|
||||
ellAdd(&errnumlist,(ELLNODE*)pNew);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "errlog.h"
|
||||
#include "logClient.h"
|
||||
#include "iocLog.h"
|
||||
#include "epicsExit.h"
|
||||
|
||||
int iocLogDisable = 0;
|
||||
|
||||
@@ -75,6 +76,14 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientDestroy()
|
||||
*/
|
||||
static void iocLogClientDestroy (logClientId id)
|
||||
{
|
||||
errlogRemoveListener (logClientSendMessage);
|
||||
}
|
||||
|
||||
/*
|
||||
* iocLogClientInit()
|
||||
*/
|
||||
@@ -91,7 +100,8 @@ static logClientId iocLogClientInit (void)
|
||||
}
|
||||
id = logClientCreate (addr, port);
|
||||
if (id != NULL) {
|
||||
errlogAddListener ( logClientSendMessage, id );
|
||||
errlogAddListener (logClientSendMessage, id);
|
||||
epicsAtExit (iocLogClientDestroy, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@@ -139,13 +149,3 @@ logClientId epicsShareAPI logClientInit (void)
|
||||
{
|
||||
return iocLogClientInit ();
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientSendMessage (); deprecated
|
||||
*/
|
||||
void logClientSendMessage ( logClientId id, const char * message )
|
||||
{
|
||||
if ( !iocLogDisable ) {
|
||||
logClientSend (id, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbDefs.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "iocLog.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsTime.h"
|
||||
@@ -42,6 +43,7 @@ typedef struct {
|
||||
SOCKET sock;
|
||||
epicsThreadId restartThreadId;
|
||||
epicsEventId stateChangeNotify;
|
||||
epicsEventId shutdownNotify;
|
||||
unsigned connectCount;
|
||||
unsigned nextMsgIndex;
|
||||
unsigned connected;
|
||||
@@ -51,9 +53,13 @@ typedef struct {
|
||||
} logClient;
|
||||
|
||||
static const double LOG_RESTART_DELAY = 5.0; /* sec */
|
||||
static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */
|
||||
static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */
|
||||
|
||||
/*
|
||||
* If set using iocLogPrefix() this string is prepended to all log messages:
|
||||
*/
|
||||
static char* logClientPrefix = NULL;
|
||||
|
||||
/*
|
||||
* logClientClose ()
|
||||
*/
|
||||
@@ -77,8 +83,6 @@ static void logClientClose ( logClient *pClient )
|
||||
pClient->sock = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
pClient->nextMsgIndex = 0u;
|
||||
memset ( pClient->msgBuf, '\0', sizeof ( pClient->msgBuf ) );
|
||||
pClient->connected = 0u;
|
||||
|
||||
/*
|
||||
@@ -106,6 +110,7 @@ static void logClientDestroy (logClientId id)
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
pClient->shutdown = 1u;
|
||||
epicsMutexUnlock ( pClient->mutex );
|
||||
epicsEventSignal ( pClient->shutdownNotify );
|
||||
|
||||
/* unblock log client thread blocking in send() or connect() */
|
||||
interruptInfo =
|
||||
@@ -150,112 +155,109 @@ static void logClientDestroy (logClientId id)
|
||||
logClientClose ( pClient );
|
||||
|
||||
epicsMutexDestroy ( pClient->mutex );
|
||||
|
||||
epicsEventDestroy ( pClient->stateChangeNotify );
|
||||
epicsEventDestroy ( pClient->shutdownNotify );
|
||||
|
||||
free ( pClient );
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientCheckConnection
|
||||
*/
|
||||
static void logClientCheckConnection( logClient * pClient )
|
||||
{
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
while ( pClient->connected ) {
|
||||
struct timeval timeout = { 0, 0 };
|
||||
fd_set set;
|
||||
char buffer[256];
|
||||
|
||||
FD_ZERO ( &set );
|
||||
FD_SET ( pClient->sock, &set );
|
||||
if ( select ( pClient->sock + 1, &set, NULL, NULL, &timeout ) == 0)
|
||||
break;
|
||||
if ( recv ( pClient->sock, buffer, sizeof ( buffer ), 0 ) == 0 ) {
|
||||
fprintf ( stderr, "log client: connection closed by server \"%s\"\n",
|
||||
pClient->name );
|
||||
logClientClose ( pClient );
|
||||
break;
|
||||
}
|
||||
}
|
||||
epicsMutexUnlock ( pClient->mutex );
|
||||
}
|
||||
|
||||
/*
|
||||
* This method requires the pClient->mutex be owned already.
|
||||
*/
|
||||
static void sendMessageChunk(logClient * pClient, const char * message) {
|
||||
unsigned strSize;
|
||||
|
||||
strSize = strlen ( message );
|
||||
while ( strSize ) {
|
||||
unsigned msgBufBytesLeft =
|
||||
sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
|
||||
|
||||
if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected)
|
||||
{
|
||||
/* buffer is full, thus flush it */
|
||||
logClientCheckConnection( pClient );
|
||||
logClientFlush ( pClient );
|
||||
msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
|
||||
}
|
||||
if ( msgBufBytesLeft == 0u ) {
|
||||
fprintf ( stderr, "log client: messages to \"%s\" are lost\n",
|
||||
pClient->name );
|
||||
break;
|
||||
}
|
||||
if ( msgBufBytesLeft > strSize) msgBufBytesLeft = strSize;
|
||||
memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
|
||||
message, msgBufBytesLeft );
|
||||
pClient->nextMsgIndex += msgBufBytesLeft;
|
||||
strSize -= msgBufBytesLeft;
|
||||
message += msgBufBytesLeft;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* logClientSend ()
|
||||
*/
|
||||
void epicsShareAPI logClientSend ( logClientId id, const char * message )
|
||||
{
|
||||
logClient * pClient = ( logClient * ) id;
|
||||
unsigned strSize;
|
||||
|
||||
if ( ! pClient || ! message ) {
|
||||
return;
|
||||
}
|
||||
|
||||
strSize = strlen ( message );
|
||||
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
|
||||
while ( strSize ) {
|
||||
unsigned msgBufBytesLeft =
|
||||
sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
|
||||
|
||||
if ( strSize > msgBufBytesLeft ) {
|
||||
int status;
|
||||
|
||||
if ( ! pClient->connected ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( msgBufBytesLeft > 0u ) {
|
||||
memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
|
||||
message, msgBufBytesLeft );
|
||||
pClient->nextMsgIndex += msgBufBytesLeft;
|
||||
strSize -= msgBufBytesLeft;
|
||||
message += msgBufBytesLeft;
|
||||
}
|
||||
|
||||
status = send ( pClient->sock, pClient->msgBuf,
|
||||
pClient->nextMsgIndex, 0 );
|
||||
if ( status > 0 ) {
|
||||
unsigned nSent = (unsigned) status;
|
||||
if ( nSent < pClient->nextMsgIndex ) {
|
||||
unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
|
||||
memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
|
||||
newNextMsgIndex );
|
||||
pClient->nextMsgIndex = newNextMsgIndex;
|
||||
}
|
||||
else {
|
||||
pClient->nextMsgIndex = 0u;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( ! pClient->shutdown ) {
|
||||
char sockErrBuf[64];
|
||||
if ( status ) {
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
}
|
||||
else {
|
||||
strcpy ( sockErrBuf, "server initiated disconnect" );
|
||||
}
|
||||
fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
|
||||
pClient->name, sockErrBuf );
|
||||
}
|
||||
logClientClose ( pClient );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
|
||||
message, strSize );
|
||||
pClient->nextMsgIndex += strSize;
|
||||
break;
|
||||
}
|
||||
if (logClientPrefix) {
|
||||
sendMessageChunk(pClient, logClientPrefix);
|
||||
}
|
||||
|
||||
sendMessageChunk(pClient, message);
|
||||
|
||||
epicsMutexUnlock (pClient->mutex);
|
||||
}
|
||||
|
||||
|
||||
void epicsShareAPI logClientFlush ( logClientId id )
|
||||
{
|
||||
unsigned nSent = 0u;
|
||||
|
||||
logClient * pClient = ( logClient * ) id;
|
||||
|
||||
if ( ! pClient ) {
|
||||
if ( ! pClient || ! pClient->connected ) {
|
||||
return;
|
||||
}
|
||||
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
|
||||
while ( pClient->nextMsgIndex && pClient->connected ) {
|
||||
int status = send ( pClient->sock, pClient->msgBuf,
|
||||
pClient->nextMsgIndex, 0 );
|
||||
while ( nSent < pClient->nextMsgIndex && pClient->connected ) {
|
||||
int status = send ( pClient->sock, pClient->msgBuf + nSent,
|
||||
pClient->nextMsgIndex - nSent, 0 );
|
||||
if ( status > 0 ) {
|
||||
unsigned nSent = (unsigned) status;
|
||||
if ( nSent < pClient->nextMsgIndex ) {
|
||||
unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
|
||||
memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
|
||||
newNextMsgIndex );
|
||||
pClient->nextMsgIndex = newNextMsgIndex;
|
||||
}
|
||||
else {
|
||||
pClient->nextMsgIndex = 0u;
|
||||
}
|
||||
nSent += (unsigned) status;
|
||||
}
|
||||
else {
|
||||
if ( ! pClient->shutdown ) {
|
||||
@@ -273,6 +275,11 @@ void epicsShareAPI logClientFlush ( logClientId id )
|
||||
break;
|
||||
}
|
||||
}
|
||||
pClient->nextMsgIndex -= nSent;
|
||||
if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
|
||||
memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
|
||||
pClient->nextMsgIndex );
|
||||
}
|
||||
epicsMutexUnlock ( pClient->mutex );
|
||||
}
|
||||
|
||||
@@ -377,20 +384,6 @@ static void logClientConnect (logClient *pClient)
|
||||
fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* we don't need full-duplex (clients only write), so we shutdown
|
||||
* the read end of our socket
|
||||
*/
|
||||
status = shutdown (pClient->sock, SHUT_RD);
|
||||
if (status < 0) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n",
|
||||
__FILE__, __LINE__, pClient->sock, sockErrBuf);
|
||||
/* not fatal (although it shouldn't happen) */
|
||||
}
|
||||
|
||||
/*
|
||||
* set how long we will wait for the TCP state machine
|
||||
* to clean up when we issue a close(). This
|
||||
@@ -430,20 +423,21 @@ static void logClientRestart ( logClientId id )
|
||||
/* SMP safe state inspection */
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
while ( ! pClient->shutdown ) {
|
||||
unsigned isConn;
|
||||
unsigned isConn, dataToSend;
|
||||
|
||||
logClientCheckConnection( pClient );
|
||||
|
||||
isConn = pClient->connected;
|
||||
dataToSend = pClient->nextMsgIndex;
|
||||
|
||||
epicsMutexUnlock ( pClient->mutex );
|
||||
|
||||
if ( isConn ) {
|
||||
if ( dataToSend ) {
|
||||
if ( ! isConn ) logClientConnect ( pClient );
|
||||
logClientFlush ( pClient );
|
||||
}
|
||||
else {
|
||||
logClientConnect ( pClient );
|
||||
}
|
||||
|
||||
epicsThreadSleep ( LOG_RESTART_DELAY );
|
||||
|
||||
epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY);
|
||||
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
}
|
||||
@@ -459,9 +453,7 @@ static void logClientRestart ( logClientId id )
|
||||
logClientId epicsShareAPI logClientCreate (
|
||||
struct in_addr server_addr, unsigned short server_port)
|
||||
{
|
||||
epicsTimeStamp begin, current;
|
||||
logClient *pClient;
|
||||
double diff;
|
||||
|
||||
pClient = calloc (1, sizeof (*pClient));
|
||||
if (pClient==NULL) {
|
||||
@@ -486,14 +478,22 @@ logClientId epicsShareAPI logClientCreate (
|
||||
pClient->shutdownConfirm = 0;
|
||||
|
||||
epicsAtExit (logClientDestroy, (void*) pClient);
|
||||
|
||||
|
||||
pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty);
|
||||
if ( ! pClient->stateChangeNotify ) {
|
||||
epicsMutexDestroy ( pClient->mutex );
|
||||
free ( pClient );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
pClient->shutdownNotify = epicsEventCreate (epicsEventEmpty);
|
||||
if ( ! pClient->shutdownNotify ) {
|
||||
epicsMutexDestroy ( pClient->mutex );
|
||||
epicsEventDestroy ( pClient->stateChangeNotify );
|
||||
free ( pClient );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pClient->restartThreadId = epicsThreadCreate (
|
||||
"logRestart", epicsThreadPriorityLow,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
@@ -501,33 +501,12 @@ logClientId epicsShareAPI logClientCreate (
|
||||
if ( pClient->restartThreadId == NULL ) {
|
||||
epicsMutexDestroy ( pClient->mutex );
|
||||
epicsEventDestroy ( pClient->stateChangeNotify );
|
||||
epicsEventDestroy ( pClient->shutdownNotify );
|
||||
free (pClient);
|
||||
fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* attempt to synchronize with circuit connect
|
||||
*/
|
||||
epicsTimeGetCurrent ( & begin );
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
do {
|
||||
epicsMutexUnlock ( pClient->mutex );
|
||||
epicsEventWaitWithTimeout (
|
||||
pClient->stateChangeNotify,
|
||||
LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 );
|
||||
epicsTimeGetCurrent ( & current );
|
||||
diff = epicsTimeDiffInSeconds ( & current, & begin );
|
||||
epicsMutexMustLock ( pClient->mutex );
|
||||
}
|
||||
while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
|
||||
epicsMutexUnlock ( pClient->mutex );
|
||||
|
||||
if ( ! pClient->connected ) {
|
||||
fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n",
|
||||
pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
|
||||
}
|
||||
|
||||
return (void *) pClient;
|
||||
}
|
||||
|
||||
@@ -537,6 +516,9 @@ logClientId epicsShareAPI logClientCreate (
|
||||
void epicsShareAPI logClientShow (logClientId id, unsigned level)
|
||||
{
|
||||
logClient *pClient = (logClient *) id;
|
||||
if ( ! pClient ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pClient->connected ) {
|
||||
printf ("log client: connected to log server at \"%s\"\n", pClient->name);
|
||||
@@ -550,5 +532,46 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
|
||||
pClient->sock==INVALID_SOCKET?"INVALID":"OK",
|
||||
pClient->connectCount);
|
||||
}
|
||||
|
||||
if (logClientPrefix) {
|
||||
printf ("log client: prefix is \"%s\"\n", logClientPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* logClientSendMessage (); deprecated
|
||||
*/
|
||||
void logClientSendMessage ( logClientId id, const char * message )
|
||||
{
|
||||
if ( !iocLogDisable ) {
|
||||
logClientSend (id, message);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* iocLogPrefix()
|
||||
*/
|
||||
void epicsShareAPI iocLogPrefix(const char * prefix)
|
||||
{
|
||||
|
||||
/* If we have already established a log prefix, don't let the user change
|
||||
* it. The iocLogPrefix command is expected to be run from the IOC startup
|
||||
* script during initialization; the prefix can't be changed once it has
|
||||
* been set.
|
||||
*/
|
||||
|
||||
if (logClientPrefix) {
|
||||
printf ("iocLogPrefix: The prefix was already set to \"%s\" "
|
||||
"and can't be changed.\n", logClientPrefix);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
unsigned prefixLen = strlen(prefix);
|
||||
if (prefixLen > 0) {
|
||||
char * localCopy = malloc(prefixLen+1);
|
||||
strcpy(localCopy, prefix);
|
||||
logClientPrefix = localCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ epicsShareFunc logClientId epicsShareAPI logClientCreate (
|
||||
epicsShareFunc void epicsShareAPI logClientSend (logClientId id, const char *message);
|
||||
epicsShareFunc void epicsShareAPI logClientShow (logClientId id, unsigned level);
|
||||
epicsShareFunc void epicsShareAPI logClientFlush (logClientId id);
|
||||
epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix);
|
||||
|
||||
/* deprecated interface; retained for backward compatibility */
|
||||
/* note: implementations are in iocLog.c, not logClient.c */
|
||||
|
||||
@@ -558,6 +558,186 @@ static MAC_ENTRY *create( MAC_HANDLE *handle, const char *name, int special )
|
||||
return entry;
|
||||
}
|
||||
|
||||
#define SUCCESS 0
|
||||
#define NOVALUE 1
|
||||
#define UNTERMINATED 2
|
||||
#define DIVZERO 3
|
||||
|
||||
static int parseExpr( const char** pp, int* v, int level );
|
||||
|
||||
/* Value is a number or an expression in () */
|
||||
static int parseValue( const char** pp, int* v )
|
||||
{
|
||||
int status;
|
||||
int val;
|
||||
const char *p = *pp;
|
||||
int neg = 0;
|
||||
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p == '+' || *p == '-') neg = *p++ == '-';
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p == '(')
|
||||
{
|
||||
p++;
|
||||
if ((status = parseExpr(&p, &val, 0)) != SUCCESS) return status;
|
||||
if (*p++ != ')')
|
||||
{
|
||||
printf("macLib: missing ) after '%s'\n", *pp);
|
||||
return UNTERMINATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char* e;
|
||||
val = strtol(p, &e, 0);
|
||||
if (e == p) return NOVALUE;
|
||||
p = e;
|
||||
}
|
||||
if (neg) val = -val;
|
||||
*pp = p;
|
||||
*v = val;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* Expr is a sum or product of Values or a conditional */
|
||||
static int parseExpr( const char** pp, int* v, int level )
|
||||
{
|
||||
const char *p = *pp;
|
||||
int o = 0;
|
||||
int val0, val1, val2;
|
||||
int status = SUCCESS;
|
||||
int stat1, stat2;
|
||||
|
||||
val0 = 0;
|
||||
/* handle sums and differences */
|
||||
do {
|
||||
if ((stat1 = parseValue(&p, &val1)) != SUCCESS)
|
||||
{
|
||||
if (o && stat1 == NOVALUE)
|
||||
printf ("macLib: missing operand after '%c'\n", o);
|
||||
return stat1;
|
||||
}
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
o = *p;
|
||||
/* handle products and quotients */
|
||||
while (o == '*' || o == '/' || o == '%')
|
||||
{
|
||||
p++;
|
||||
if ((stat2 = parseValue(&p, &val2)) != SUCCESS)
|
||||
{
|
||||
if (stat2 == NOVALUE)
|
||||
printf ("macLib: missing operand after '%c'\n", o);
|
||||
return stat2;
|
||||
}
|
||||
if (o == '*') val1 *= val2;
|
||||
else if (val2 == 0)
|
||||
{
|
||||
status = DIVZERO;
|
||||
val1 = 1;
|
||||
}
|
||||
else if (o == '/') val1 /= val2;
|
||||
else val1 %= val2;
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
o = *p;
|
||||
}
|
||||
val0 += val1;
|
||||
} while (o == '+' || o == '-');
|
||||
|
||||
/* handle comparisons */
|
||||
o = *p;
|
||||
if (o == '<' || o == '>')
|
||||
{
|
||||
p++;
|
||||
if ((stat1 = parseExpr(&p, &val1, 1)) != SUCCESS)
|
||||
{
|
||||
if (stat1 == NOVALUE)
|
||||
printf ("macLib: missing expression after '%c'\n", o);
|
||||
return stat1;
|
||||
}
|
||||
if (o == '<')
|
||||
val0 = (val0 < val1);
|
||||
else
|
||||
val0 = (val0 > val1);
|
||||
}
|
||||
|
||||
/* handle conditionals */
|
||||
if (*p == '?' && level == 0)
|
||||
{
|
||||
p++;
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p != ':')
|
||||
{
|
||||
stat1 = parseExpr(&p, &val1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
val1 = val0;
|
||||
stat1 = status;
|
||||
}
|
||||
if (*p != ':')
|
||||
{
|
||||
printf("macLib: missing : after '%s'\n", *pp);
|
||||
return UNTERMINATED;
|
||||
}
|
||||
p++;
|
||||
stat2 = parseExpr(&p, &val2, 0);
|
||||
status = val0 ? stat1 : stat2;
|
||||
val0 = val0 ? val1 : val2;
|
||||
}
|
||||
|
||||
*v = val0;
|
||||
*pp = p;
|
||||
return status;
|
||||
}
|
||||
|
||||
static MAC_ENTRY *evalExpr( MAC_HANDLE *handle, const char *expr )
|
||||
{
|
||||
MAC_ENTRY *entry = NULL;
|
||||
int status;
|
||||
const char* p = expr;
|
||||
int value;
|
||||
char valuestr[40];
|
||||
char format[20] = "%d";
|
||||
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p == '%')
|
||||
{
|
||||
int i = 1;
|
||||
p++;
|
||||
while (i < sizeof(format) && strchr(" #-+0", *p))
|
||||
format[i++] = *p++;
|
||||
while (i < sizeof(format) && strchr("0123456789", *p))
|
||||
format[i++] = *p++;
|
||||
if (i < sizeof(format) && strchr("diouxXc", *p))
|
||||
{
|
||||
format[i++] = *p++;
|
||||
format[i] = 0;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
status = parseExpr(&p, &value, 0);
|
||||
if (status == DIVZERO)
|
||||
printf ("macLib: division by zero\n");
|
||||
if (status != SUCCESS)
|
||||
return NULL;
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p)
|
||||
{
|
||||
printf("macLib: rubbish at end of expression: %s\n", p);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(valuestr, format, value);
|
||||
entry = create( handle, expr, TRUE );
|
||||
if ( entry )
|
||||
{
|
||||
entry->type = "calculation";
|
||||
if ( rawval( handle, entry, valuestr ) == NULL )
|
||||
return NULL;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up macro entry with matching "special" attribute by name
|
||||
*/
|
||||
@@ -569,6 +749,10 @@ static MAC_ENTRY *lookup( MAC_HANDLE *handle, const char *name, int special )
|
||||
printf( "lookup-> level = %d, name = %s, special = %d\n",
|
||||
handle->level, name, special );
|
||||
|
||||
if ( (special == FALSE) ) {
|
||||
entry = evalExpr( handle, name );
|
||||
if (entry) return entry;
|
||||
}
|
||||
/* search backwards so scoping works */
|
||||
for ( entry = last( handle ); entry != NULL; entry = previous( entry ) ) {
|
||||
if ( entry->special != special )
|
||||
@@ -688,6 +872,7 @@ static void trans( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
|
||||
/* return immediately if raw value is NULL */
|
||||
if ( *rawval == NULL ) return;
|
||||
|
||||
|
||||
/* discard quotes and escapes if level is > 0 (i.e. if these aren't
|
||||
the user's quotes and escapes) */
|
||||
discard = ( level > 0 );
|
||||
|
||||
32
src/libCom/osi/epicsSpin.h
Normal file
32
src/libCom/osi/epicsSpin.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef epicsSpinh
|
||||
#define epicsSpinh
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct epicsSpin *epicsSpinId;
|
||||
|
||||
epicsShareFunc epicsSpinId epicsSpinCreate(void);
|
||||
epicsShareFunc epicsSpinId epicsSpinMustCreate(void);
|
||||
epicsShareFunc void epicsSpinDestroy(epicsSpinId);
|
||||
|
||||
epicsShareFunc void epicsSpinLock(epicsSpinId);
|
||||
epicsShareFunc int epicsSpinTryLock(epicsSpinId);
|
||||
epicsShareFunc void epicsSpinUnlock(epicsSpinId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* epicsSpinh */
|
||||
@@ -12,12 +12,12 @@
|
||||
#ifndef epicsStdioRedirecth
|
||||
#define epicsStdioRedirecth
|
||||
|
||||
#include <epicsStdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <epicsStdio.h>
|
||||
|
||||
#undef stdin
|
||||
#define stdin epicsGetStdin()
|
||||
#undef stdout
|
||||
|
||||
876
src/libCom/osi/os/Linux/osdThread.c
Normal file
876
src/libCom/osi/os/Linux/osdThread.c
Normal file
@@ -0,0 +1,876 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* epicsThread.c */
|
||||
|
||||
/* Author: Marty Kraimer Date: 18JAN2000 */
|
||||
|
||||
/* This is a posix implementation of epicsThread */
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStdio.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsThread.h"
|
||||
#include "cantProceed.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsExit.h"
|
||||
|
||||
static int mutexLock(pthread_mutex_t *id)
|
||||
{
|
||||
int status;
|
||||
|
||||
while(1) {
|
||||
status = pthread_mutex_lock(id);
|
||||
if(status!=EINTR) return status;
|
||||
fprintf(stderr,"pthread_mutex_lock returned EINTR. Violates SUSv3\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
#undef _POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
#endif
|
||||
|
||||
typedef struct commonAttr{
|
||||
pthread_attr_t attr;
|
||||
struct sched_param schedParam;
|
||||
int maxPriority;
|
||||
int minPriority;
|
||||
int schedPolicy;
|
||||
int usePolicy;
|
||||
} commonAttr;
|
||||
|
||||
typedef struct epicsThreadOSD {
|
||||
ELLNODE node;
|
||||
pthread_t tid;
|
||||
pid_t lwpId;
|
||||
pthread_attr_t attr;
|
||||
struct sched_param schedParam;
|
||||
EPICSTHREADFUNC createFunc;
|
||||
void *createArg;
|
||||
epicsEventId suspendEvent;
|
||||
int isSuspended;
|
||||
int isEpicsThread;
|
||||
int isFifoScheduled;
|
||||
int isOnThreadList;
|
||||
unsigned int osiPriority;
|
||||
char *name;
|
||||
} epicsThreadOSD;
|
||||
|
||||
#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
typedef struct {
|
||||
int min_pri, max_pri;
|
||||
int policy;
|
||||
int ok;
|
||||
} priAvailable;
|
||||
#endif
|
||||
|
||||
static pthread_key_t getpthreadInfo;
|
||||
static pthread_mutex_t onceLock;
|
||||
static pthread_mutex_t listLock;
|
||||
static ELLLIST pthreadList = ELLLIST_INIT;
|
||||
static commonAttr *pcommonAttr = 0;
|
||||
static int epicsThreadOnceCalled = 0;
|
||||
|
||||
static epicsThreadOSD *createImplicit(void);
|
||||
|
||||
#define checkStatus(status,message) \
|
||||
if((status)) {\
|
||||
errlogPrintf("%s error %s\n",(message),strerror((status))); \
|
||||
}
|
||||
|
||||
#define checkStatusQuit(status,message,method) \
|
||||
if(status) { \
|
||||
errlogPrintf("%s error %s\n",(message),strerror((status))); \
|
||||
cantProceed((method)); \
|
||||
}
|
||||
|
||||
/* The following are for use by once, which is only invoked from epicsThreadInit*/
|
||||
/* Until epicsThreadInit completes errlogInit will not work */
|
||||
/* It must also be used by init_threadInfo otherwise errlogInit could get */
|
||||
/* called recursively */
|
||||
#define checkStatusOnce(status,message) \
|
||||
if((status)) {\
|
||||
fprintf(stderr,"%s error %s\n",(message),strerror((status))); }
|
||||
|
||||
#define checkStatusOnceQuit(status,message,method) \
|
||||
if(status) { \
|
||||
fprintf(stderr,"%s error %s",(message),strerror((status))); \
|
||||
fprintf(stderr," %s\n",method); \
|
||||
fprintf(stderr,"epicsThreadInit cant proceed. Program exiting\n"); \
|
||||
exit(-1);\
|
||||
}
|
||||
|
||||
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
static int getOssPriorityValue(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
double maxPriority,minPriority,slope,oss;
|
||||
|
||||
if(pcommonAttr->maxPriority==pcommonAttr->minPriority)
|
||||
return(pcommonAttr->maxPriority);
|
||||
maxPriority = (double)pcommonAttr->maxPriority;
|
||||
minPriority = (double)pcommonAttr->minPriority;
|
||||
slope = (maxPriority - minPriority)/100.0;
|
||||
oss = (double)pthreadInfo->osiPriority * slope + minPriority;
|
||||
return((int)oss);
|
||||
}
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
static void setSchedulingPolicy(epicsThreadOSD *pthreadInfo,int policy)
|
||||
{
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int status;
|
||||
|
||||
if(!pcommonAttr->usePolicy) return;
|
||||
|
||||
status = pthread_attr_getschedparam(
|
||||
&pthreadInfo->attr,&pthreadInfo->schedParam);
|
||||
checkStatusOnce(status,"pthread_attr_getschedparam");
|
||||
pthreadInfo->schedParam.sched_priority = getOssPriorityValue(pthreadInfo);
|
||||
status = pthread_attr_setschedpolicy(
|
||||
&pthreadInfo->attr,policy);
|
||||
checkStatusOnce(status,"pthread_attr_setschedpolicy");
|
||||
status = pthread_attr_setschedparam(
|
||||
&pthreadInfo->attr,&pthreadInfo->schedParam);
|
||||
checkStatusOnce(status,"pthread_attr_setschedparam");
|
||||
status = pthread_attr_setinheritsched(
|
||||
&pthreadInfo->attr,PTHREAD_EXPLICIT_SCHED);
|
||||
checkStatusOnce(status,"pthread_attr_setinheritsched");
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
}
|
||||
|
||||
static epicsThreadOSD * create_threadInfo(const char *name)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
pthreadInfo = callocMustSucceed(1,sizeof(*pthreadInfo),"create_threadInfo");
|
||||
pthreadInfo->suspendEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
pthreadInfo->name = epicsStrDup(name);
|
||||
return pthreadInfo;
|
||||
}
|
||||
|
||||
static epicsThreadOSD * init_threadInfo(const char *name,
|
||||
unsigned int priority, unsigned int stackSize,
|
||||
EPICSTHREADFUNC funptr,void *parm)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
pthreadInfo = create_threadInfo(name);
|
||||
pthreadInfo->createFunc = funptr;
|
||||
pthreadInfo->createArg = parm;
|
||||
status = pthread_attr_init(&pthreadInfo->attr);
|
||||
checkStatusOnce(status,"pthread_attr_init");
|
||||
if(status) return 0;
|
||||
status = pthread_attr_setdetachstate(
|
||||
&pthreadInfo->attr, PTHREAD_CREATE_DETACHED);
|
||||
checkStatusOnce(status,"pthread_attr_setdetachstate");
|
||||
#if defined (_POSIX_THREAD_ATTR_STACKSIZE)
|
||||
#if ! defined (OSITHREAD_USE_DEFAULT_STACK)
|
||||
status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize);
|
||||
checkStatusOnce(status,"pthread_attr_setstacksize");
|
||||
#endif /*OSITHREAD_USE_DEFAULT_STACK*/
|
||||
#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
|
||||
status = pthread_attr_setscope(&pthreadInfo->attr,PTHREAD_SCOPE_PROCESS);
|
||||
if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
|
||||
pthreadInfo->osiPriority = priority;
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
static void free_threadInfo(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo");
|
||||
if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node);
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","free_threadInfo");
|
||||
epicsEventDestroy(pthreadInfo->suspendEvent);
|
||||
status = pthread_attr_destroy(&pthreadInfo->attr);
|
||||
checkStatusQuit(status,"pthread_attr_destroy","free_threadInfo");
|
||||
free(pthreadInfo->name);
|
||||
free(pthreadInfo);
|
||||
}
|
||||
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
/*
|
||||
* The actually available range priority range (at least under linux)
|
||||
* may be restricted by resource limitations (but that is ignored
|
||||
* by sched_get_priority_max()). See bug #835138 which is fixed by
|
||||
* this code.
|
||||
*/
|
||||
|
||||
static int try_pri(int pri, int policy)
|
||||
{
|
||||
struct sched_param schedp;
|
||||
|
||||
schedp.sched_priority = pri;
|
||||
return pthread_setschedparam(pthread_self(), policy, &schedp);
|
||||
}
|
||||
|
||||
static void*
|
||||
find_pri_range(void *arg)
|
||||
{
|
||||
priAvailable *prm = arg;
|
||||
int min = sched_get_priority_min(prm->policy);
|
||||
int max = sched_get_priority_max(prm->policy);
|
||||
int low, try;
|
||||
|
||||
if ( -1 == min || -1 == max ) {
|
||||
/* something is very wrong; maintain old behavior
|
||||
* (warning message if sched_get_priority_xxx() fails
|
||||
* and use default policy's sched_priority [even if
|
||||
* that is likely to cause epicsThreadCreate to fail
|
||||
* because that priority is not suitable for SCHED_FIFO]).
|
||||
*/
|
||||
prm->min_pri = prm->max_pri = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if ( try_pri(min, prm->policy) ) {
|
||||
/* cannot create thread at minimum priority;
|
||||
* probably no permission to use SCHED_FIFO
|
||||
* at all. However, we still must return
|
||||
* a priority range accepted by the SCHED_FIFO
|
||||
* policy. Otherwise, epicsThreadCreate() cannot
|
||||
* detect the unsufficient permission (EPERM)
|
||||
* and fall back to a non-RT thread (because
|
||||
* pthread_attr_setschedparam would fail with
|
||||
* EINVAL due to the bad priority).
|
||||
*/
|
||||
prm->min_pri = prm->max_pri = min;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Binary search through available priorities.
|
||||
* The actually available range may be restricted
|
||||
* by resource limitations (but that is ignored
|
||||
* by sched_get_priority_max() [linux]).
|
||||
*/
|
||||
low = min;
|
||||
|
||||
while ( low < max ) {
|
||||
try = (max+low)/2;
|
||||
if ( try_pri(try, prm->policy) ) {
|
||||
max = try;
|
||||
} else {
|
||||
low = try + 1;
|
||||
}
|
||||
}
|
||||
|
||||
prm->min_pri = min;
|
||||
prm->max_pri = try_pri(max, prm->policy) ? max-1 : max;
|
||||
prm->ok = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void findPriorityRange(commonAttr *a_p)
|
||||
{
|
||||
priAvailable arg;
|
||||
pthread_t id;
|
||||
void *dummy;
|
||||
int status;
|
||||
|
||||
arg.policy = a_p->schedPolicy;
|
||||
arg.ok = 0;
|
||||
|
||||
status = pthread_create(&id, 0, find_pri_range, &arg);
|
||||
checkStatusQuit(status, "pthread_create","epicsThreadInit");
|
||||
|
||||
status = pthread_join(id, &dummy);
|
||||
checkStatusQuit(status, "pthread_join","epicsThreadInit");
|
||||
|
||||
a_p->minPriority = arg.min_pri;
|
||||
a_p->maxPriority = arg.max_pri;
|
||||
a_p->usePolicy = arg.ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void once(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
pthread_key_create(&getpthreadInfo,0);
|
||||
status = epicsPosixMutexInit(&onceLock,posixMutexDefault);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
|
||||
status = epicsPosixMutexInit(&listLock,posixMutexDefault);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
|
||||
pcommonAttr = calloc(1,sizeof(commonAttr));
|
||||
if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit");
|
||||
status = pthread_attr_init(&pcommonAttr->attr);
|
||||
checkStatusOnceQuit(status,"pthread_attr_init","epicsThreadInit");
|
||||
status = pthread_attr_setdetachstate(
|
||||
&pcommonAttr->attr, PTHREAD_CREATE_DETACHED);
|
||||
checkStatusOnce(status,"pthread_attr_setdetachstate");
|
||||
status = pthread_attr_setscope(&pcommonAttr->attr,PTHREAD_SCOPE_PROCESS);
|
||||
if(errVerbose) checkStatusOnce(status,"pthread_attr_setscope");
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
status = pthread_attr_setschedpolicy(
|
||||
&pcommonAttr->attr,SCHED_FIFO);
|
||||
checkStatusOnce(status,"pthread_attr_setschedpolicy");
|
||||
status = pthread_attr_getschedpolicy(
|
||||
&pcommonAttr->attr,&pcommonAttr->schedPolicy);
|
||||
checkStatusOnce(status,"pthread_attr_getschedpolicy");
|
||||
status = pthread_attr_getschedparam(
|
||||
&pcommonAttr->attr,&pcommonAttr->schedParam);
|
||||
checkStatusOnce(status,"pthread_attr_getschedparam");
|
||||
|
||||
findPriorityRange(pcommonAttr);
|
||||
|
||||
if(pcommonAttr->maxPriority == -1) {
|
||||
pcommonAttr->maxPriority = pcommonAttr->schedParam.sched_priority;
|
||||
fprintf(stderr,"sched_get_priority_max failed set to %d\n",
|
||||
pcommonAttr->maxPriority);
|
||||
}
|
||||
if(pcommonAttr->minPriority == -1) {
|
||||
pcommonAttr->minPriority = pcommonAttr->schedParam.sched_priority;
|
||||
fprintf(stderr,"sched_get_priority_min failed set to %d\n",
|
||||
pcommonAttr->maxPriority);
|
||||
}
|
||||
#else
|
||||
if(errVerbose) fprintf(stderr,"task priorities are not implemented\n");
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0);
|
||||
pthreadInfo->lwpId = syscall(SYS_gettid);
|
||||
status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
|
||||
checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit");
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadInit");
|
||||
ellAdd(&pthreadList,&pthreadInfo->node);
|
||||
pthreadInfo->isOnThreadList = 1;
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadInit");
|
||||
status = atexit(epicsExitCallAtExits);
|
||||
checkStatusOnce(status,"atexit");
|
||||
epicsThreadOnceCalled = 1;
|
||||
}
|
||||
|
||||
static void * start_routine(void *arg)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg;
|
||||
int status;
|
||||
sigset_t blockAllSig;
|
||||
char comm[16];
|
||||
|
||||
/* Set the name of the thread's process. Limited to 16 characters. */
|
||||
snprintf(comm, sizeof(comm), "%s", pthreadInfo->name);
|
||||
prctl(PR_SET_NAME, comm, 0l, 0l, 0l);
|
||||
pthreadInfo->lwpId = syscall(SYS_gettid);
|
||||
|
||||
sigfillset(&blockAllSig);
|
||||
pthread_sigmask(SIG_SETMASK,&blockAllSig,NULL);
|
||||
status = pthread_setspecific(getpthreadInfo,arg);
|
||||
checkStatusQuit(status,"pthread_setspecific","start_routine");
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","start_routine");
|
||||
ellAdd(&pthreadList,&pthreadInfo->node);
|
||||
pthreadInfo->isOnThreadList = 1;
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","start_routine");
|
||||
|
||||
(*pthreadInfo->createFunc)(pthreadInfo->createArg);
|
||||
|
||||
epicsExitCallAtThreadExits ();
|
||||
|
||||
free_threadInfo(pthreadInfo);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void epicsThreadInit(void)
|
||||
{
|
||||
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
||||
int status = pthread_once(&once_control,once);
|
||||
checkStatusQuit(status,"pthread_once","epicsThreadInit");
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass)
|
||||
{
|
||||
#if ! defined (_POSIX_THREAD_ATTR_STACKSIZE)
|
||||
return 0;
|
||||
#elif defined (OSITHREAD_USE_DEFAULT_STACK)
|
||||
return 0;
|
||||
#else
|
||||
#define STACK_SIZE(f) (f * 0x10000 * sizeof(void *))
|
||||
static const unsigned stackSizeTable[epicsThreadStackBig+1] = {
|
||||
STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4)
|
||||
};
|
||||
if (stackSizeClass<epicsThreadStackSmall) {
|
||||
errlogPrintf("epicsThreadGetStackSize illegal argument (too small)");
|
||||
return stackSizeTable[epicsThreadStackBig];
|
||||
}
|
||||
|
||||
if (stackSizeClass>epicsThreadStackBig) {
|
||||
errlogPrintf("epicsThreadGetStackSize illegal argument (too large)");
|
||||
return stackSizeTable[epicsThreadStackBig];
|
||||
}
|
||||
|
||||
return stackSizeTable[stackSizeClass];
|
||||
#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
|
||||
{
|
||||
static struct epicsThreadOSD threadOnceComplete;
|
||||
#define EPICS_THREAD_ONCE_DONE &threadOnceComplete
|
||||
int status;
|
||||
|
||||
epicsThreadInit();
|
||||
status = mutexLock(&onceLock);
|
||||
if(status) {
|
||||
fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
|
||||
strerror(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (*id != EPICS_THREAD_ONCE_DONE) {
|
||||
if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
|
||||
*id = epicsThreadGetIdSelf(); /* mark active */
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
|
||||
func(arg);
|
||||
status = mutexLock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
|
||||
*id = EPICS_THREAD_ONCE_DONE; /* mark done */
|
||||
} else if (*id == epicsThreadGetIdSelf()) {
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
|
||||
cantProceed("Recursive epicsThreadOnce() initialization\n");
|
||||
} else
|
||||
while (*id != EPICS_THREAD_ONCE_DONE) {
|
||||
/* Another thread is in the above func(arg) call. */
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
|
||||
epicsThreadSleep(epicsThreadSleepQuantum());
|
||||
status = mutexLock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
|
||||
}
|
||||
}
|
||||
status = pthread_mutex_unlock(&onceLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name,
|
||||
unsigned int priority, unsigned int stackSize,
|
||||
EPICSTHREADFUNC funptr,void *parm)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
sigset_t blockAllSig, oldSig;
|
||||
|
||||
epicsThreadInit();
|
||||
assert(pcommonAttr);
|
||||
sigfillset(&blockAllSig);
|
||||
pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig);
|
||||
pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm);
|
||||
if(pthreadInfo==0) return 0;
|
||||
pthreadInfo->isEpicsThread = 1;
|
||||
setSchedulingPolicy(pthreadInfo,SCHED_FIFO);
|
||||
pthreadInfo->isFifoScheduled = 1;
|
||||
status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
|
||||
start_routine,pthreadInfo);
|
||||
if(status==EPERM){
|
||||
/* Try again without SCHED_FIFO*/
|
||||
free_threadInfo(pthreadInfo);
|
||||
pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm);
|
||||
if(pthreadInfo==0) return 0;
|
||||
pthreadInfo->isEpicsThread = 1;
|
||||
status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr,
|
||||
start_routine,pthreadInfo);
|
||||
}
|
||||
checkStatusOnce(status,"pthread_create");
|
||||
if(status) {
|
||||
free_threadInfo(pthreadInfo);
|
||||
return 0;
|
||||
}
|
||||
status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL);
|
||||
checkStatusOnce(status,"pthread_sigmask");
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup routine for threads not created by epicsThreadCreate().
|
||||
*/
|
||||
/* static void nonEPICSthreadCleanup(void *arg)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo = (epicsThreadOSD *)arg;
|
||||
|
||||
free(pthreadInfo->name);
|
||||
free(pthreadInfo);
|
||||
} */
|
||||
|
||||
/*
|
||||
* Create dummy context for threads not created by epicsThreadCreate().
|
||||
*/
|
||||
static epicsThreadOSD *createImplicit(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
char name[64];
|
||||
pthread_t tid;
|
||||
int status;
|
||||
|
||||
tid = pthread_self();
|
||||
sprintf(name, "non-EPICS_%ld", (long)tid);
|
||||
pthreadInfo = create_threadInfo(name);
|
||||
pthreadInfo->tid = tid;
|
||||
pthreadInfo->osiPriority = 0;
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
{
|
||||
struct sched_param param;
|
||||
int policy;
|
||||
if(pthread_getschedparam(tid,&policy,¶m) == 0)
|
||||
pthreadInfo->osiPriority =
|
||||
(param.sched_priority - pcommonAttr->minPriority) * 100.0 /
|
||||
(pcommonAttr->maxPriority - pcommonAttr->minPriority + 1);
|
||||
}
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo);
|
||||
checkStatusQuit(status,"pthread_setspecific","createImplicit");
|
||||
/* pthread_cleanup_push(nonEPICSthreadCleanup, pthreadInfo); */
|
||||
return pthreadInfo;
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
pthreadInfo->isSuspended = 1;
|
||||
epicsEventMustWait(pthreadInfo->suspendEvent);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadOSD *pthreadInfo)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
pthreadInfo->isSuspended = 0;
|
||||
epicsEventSignal(pthreadInfo->suspendEvent);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadExitMain(void)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
if(pthreadInfo->createFunc) {
|
||||
errlogPrintf("called from non-main thread\n");
|
||||
cantProceed("epicsThreadExitMain");
|
||||
}
|
||||
else {
|
||||
free_threadInfo(pthreadInfo);
|
||||
pthread_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority(epicsThreadId pthreadInfo)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
return(pthreadInfo->osiPriority);
|
||||
}
|
||||
|
||||
epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void)
|
||||
{
|
||||
epicsThreadInit();
|
||||
return(epicsThreadGetPriority(epicsThreadGetIdSelf()));
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadSetPriority(epicsThreadId pthreadInfo,unsigned int priority)
|
||||
{
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int status;
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
assert(pthreadInfo);
|
||||
if(!pthreadInfo->isEpicsThread) {
|
||||
fprintf(stderr,"epicsThreadSetPriority called by non epics thread\n");
|
||||
return;
|
||||
}
|
||||
pthreadInfo->osiPriority = priority;
|
||||
if(!pthreadInfo->isFifoScheduled) return;
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
if(!pcommonAttr->usePolicy) return;
|
||||
pthreadInfo->schedParam.sched_priority = getOssPriorityValue(pthreadInfo);
|
||||
status = pthread_attr_setschedparam(
|
||||
&pthreadInfo->attr,&pthreadInfo->schedParam);
|
||||
if(errVerbose) checkStatus(status,"pthread_attr_setschedparam");
|
||||
status = pthread_setschedparam(
|
||||
pthreadInfo->tid,pcommonAttr->schedPolicy,&pthreadInfo->schedParam);
|
||||
if(errVerbose) checkStatus(status,"pthread_setschedparam");
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadHighestPriorityLevelBelow(
|
||||
unsigned int priority, unsigned *pPriorityJustBelow)
|
||||
{
|
||||
unsigned newPriority = priority - 1;
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int diff;
|
||||
diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
|
||||
if(diff<0) diff = -diff;
|
||||
if(diff>1 && diff <100) newPriority -= 100/(diff+1);
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
if (newPriority <= 99) {
|
||||
*pPriorityJustBelow = newPriority;
|
||||
return epicsThreadBooleanStatusSuccess;
|
||||
}
|
||||
return epicsThreadBooleanStatusFail;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadBooleanStatus epicsShareAPI epicsThreadLowestPriorityLevelAbove(
|
||||
unsigned int priority, unsigned *pPriorityJustAbove)
|
||||
{
|
||||
unsigned newPriority = priority + 1;
|
||||
|
||||
#if defined (_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
int diff;
|
||||
diff = pcommonAttr->maxPriority - pcommonAttr->minPriority;
|
||||
if(diff<0) diff = -diff;
|
||||
if(diff>1 && diff <100) newPriority += 100/(diff+1);
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */
|
||||
if (newPriority <= 99) {
|
||||
*pPriorityJustAbove = newPriority;
|
||||
return epicsThreadBooleanStatusSuccess;
|
||||
}
|
||||
return epicsThreadBooleanStatusFail;
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsThreadIsEqual(epicsThreadId p1, epicsThreadId p2)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
assert(p1);
|
||||
assert(p2);
|
||||
return(pthread_equal(p1->tid,p2->tid));
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsThreadIsSuspended(epicsThreadId pthreadInfo) {
|
||||
assert(epicsThreadOnceCalled);
|
||||
assert(pthreadInfo);
|
||||
return(pthreadInfo->isSuspended ? 1 : 0);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadSleep(double seconds)
|
||||
{
|
||||
struct timespec delayTime;
|
||||
struct timespec remainingTime;
|
||||
double nanoseconds;
|
||||
|
||||
if (seconds > 0) {
|
||||
delayTime.tv_sec = seconds;
|
||||
nanoseconds = (seconds - delayTime.tv_sec) *1e9;
|
||||
delayTime.tv_nsec = nanoseconds;
|
||||
}
|
||||
else {
|
||||
delayTime.tv_sec = 0;
|
||||
delayTime.tv_nsec = 0;
|
||||
}
|
||||
while (nanosleep(&delayTime, &remainingTime) == -1 &&
|
||||
errno == EINTR)
|
||||
delayTime = remainingTime;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void) {
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
assert ( pthreadInfo );
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
epicsShareFunc pthread_t epicsShareAPI epicsThreadGetPosixThreadId ( epicsThreadId threadId )
|
||||
{
|
||||
return threadId->tid;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name) {
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadGetId");
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
if(strcmp(name,pthreadInfo->name) == 0) break;
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadGetId");
|
||||
|
||||
return(pthreadInfo);
|
||||
}
|
||||
|
||||
epicsShareFunc const char epicsShareAPI *epicsThreadGetNameSelf()
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
|
||||
epicsThreadInit();
|
||||
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
|
||||
if(pthreadInfo==NULL)
|
||||
pthreadInfo = createImplicit();
|
||||
return(pthreadInfo->name);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadGetName(epicsThreadId pthreadInfo, char *name, size_t size)
|
||||
{
|
||||
assert(epicsThreadOnceCalled);
|
||||
strncpy(name, pthreadInfo->name, size-1);
|
||||
name[size-1] = '\0';
|
||||
}
|
||||
|
||||
static void showThreadInfo(epicsThreadOSD *pthreadInfo,unsigned int level)
|
||||
{
|
||||
if(!pthreadInfo) {
|
||||
fprintf(epicsGetStdout()," NAME EPICS ID "
|
||||
"LWP ID OSIPRI OSSPRI STATE\n");
|
||||
} else {
|
||||
struct sched_param param;
|
||||
int policy;
|
||||
int priority = 0;
|
||||
|
||||
if(pthreadInfo->tid) {
|
||||
int status;
|
||||
status = pthread_getschedparam(pthreadInfo->tid,&policy,¶m);
|
||||
if(!status) priority = param.sched_priority;
|
||||
}
|
||||
fprintf(epicsGetStdout(),"%16.16s %18p %8lu %3d%8d %8.8s\n",
|
||||
pthreadInfo->name,(void *)
|
||||
pthreadInfo,(unsigned long)pthreadInfo->lwpId,
|
||||
pthreadInfo->osiPriority,priority,
|
||||
pthreadInfo->isSuspended?"SUSPEND":"OK");
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
|
||||
epicsThreadInit();
|
||||
epicsThreadShow(0,level);
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadShowAll");
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
showThreadInfo(pthreadInfo,level);
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadShowAll");
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadShow(epicsThreadId showThread, unsigned int level)
|
||||
{
|
||||
epicsThreadOSD *pthreadInfo;
|
||||
int status;
|
||||
int found = 0;
|
||||
|
||||
epicsThreadInit();
|
||||
if(!showThread) {
|
||||
showThreadInfo(0,level);
|
||||
return;
|
||||
}
|
||||
status = mutexLock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_lock","epicsThreadShowAll");
|
||||
pthreadInfo=(epicsThreadOSD *)ellFirst(&pthreadList);
|
||||
while(pthreadInfo) {
|
||||
if (((epicsThreadId)pthreadInfo == showThread)
|
||||
|| ((epicsThreadId)pthreadInfo->tid == showThread)) {
|
||||
found = 1;
|
||||
showThreadInfo(pthreadInfo,level);
|
||||
}
|
||||
pthreadInfo=(epicsThreadOSD *)ellNext(&pthreadInfo->node);
|
||||
}
|
||||
status = pthread_mutex_unlock(&listLock);
|
||||
checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadShowAll");
|
||||
if (!found)
|
||||
printf("Thread %#lx (%lu) not found.\n", (unsigned long)showThread, (unsigned long)showThread);
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void)
|
||||
{
|
||||
pthread_key_t *key;
|
||||
int status;
|
||||
|
||||
epicsThreadInit();
|
||||
key = callocMustSucceed(1,sizeof(pthread_key_t),"epicsThreadPrivateCreate");
|
||||
status = pthread_key_create(key,0);
|
||||
checkStatusQuit(status,"pthread_key_create","epicsThreadPrivateCreate");
|
||||
return((epicsThreadPrivateId)key);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id)
|
||||
{
|
||||
pthread_key_t *key = (pthread_key_t *)id;
|
||||
int status;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
status = pthread_key_delete(*key);
|
||||
checkStatusQuit(status,"pthread_key_delete","epicsThreadPrivateDelete");
|
||||
free((void *)key);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsThreadPrivateSet (epicsThreadPrivateId id, void *value)
|
||||
{
|
||||
pthread_key_t *key = (pthread_key_t *)id;
|
||||
int status;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
if(errVerbose && !value)
|
||||
errlogPrintf("epicsThreadPrivateSet: setting value of 0\n");
|
||||
status = pthread_setspecific(*key,value);
|
||||
checkStatusQuit(status,"pthread_setspecific","epicsThreadPrivateSet");
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI *epicsThreadPrivateGet(epicsThreadPrivateId id)
|
||||
{
|
||||
pthread_key_t *key = (pthread_key_t *)id;
|
||||
|
||||
assert(epicsThreadOnceCalled);
|
||||
return pthread_getspecific(*key);
|
||||
}
|
||||
|
||||
epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum ()
|
||||
{
|
||||
double hz;
|
||||
hz = sysconf ( _SC_CLK_TCK );
|
||||
return 1.0 / hz;
|
||||
}
|
||||
|
||||
106
src/libCom/osi/os/RTEMS/osdSpin.c
Normal file
106
src/libCom/osi/os/RTEMS/osdSpin.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2013 Brookhaven Science Assoc. as Operator of Brookhaven
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
* Michael Davidsaver <mdavidsaver@bnl.gov>
|
||||
*
|
||||
* Inspired by Linux UP spinlocks implemention
|
||||
* include/linux/spinlock_api_up.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* RTEMS (single CPU): LOCK INTERRUPT and DISABLE PREEMPTION
|
||||
*
|
||||
* CAVEAT:
|
||||
* This implementation is intended for UP architectures only.
|
||||
*/
|
||||
|
||||
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <rtems.h>
|
||||
|
||||
#include "cantProceed.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
typedef struct epicsSpin {
|
||||
rtems_interrupt_level level;
|
||||
unsigned int locked;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
return calloc(1, sizeof(epicsSpin));
|
||||
}
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if (!ret)
|
||||
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
_Thread_Disable_dispatch();
|
||||
if (spin->locked) {
|
||||
rtems_interrupt_enable(level);
|
||||
_Thread_Enable_dispatch();
|
||||
if (!rtems_interrupt_is_in_progress()) {
|
||||
printk("epicsSpinLock(%p): Deadlock.\n", spin);
|
||||
cantProceed("Recursive lock, missed unlock or block when locked.");
|
||||
}
|
||||
else {
|
||||
printk("epicsSpinLock(%p): Deadlock in ISR.\n"
|
||||
"Recursive lock, missed unlock or block when locked.\n",
|
||||
spin);
|
||||
}
|
||||
return;
|
||||
}
|
||||
spin->level = level;
|
||||
spin->locked = 1;
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
_Thread_Disable_dispatch();
|
||||
if (spin->locked) {
|
||||
rtems_interrupt_enable(level);
|
||||
_Thread_Enable_dispatch();
|
||||
return 1;
|
||||
}
|
||||
spin->level = level;
|
||||
spin->locked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
rtems_interrupt_level level = spin->level;
|
||||
|
||||
if (!spin->locked) {
|
||||
printk("epicsSpinUnlock(%p): not locked\n", spin);
|
||||
return;
|
||||
}
|
||||
spin->level = spin->locked = 0;
|
||||
rtems_interrupt_enable (level);
|
||||
_Thread_Enable_dispatch();
|
||||
}
|
||||
84
src/libCom/osi/os/default/osdSpin.c
Normal file
84
src/libCom/osi/os/default/osdSpin.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
/*
|
||||
* Default: EPICS MUTEX IMPLEMENTATION
|
||||
*/
|
||||
|
||||
typedef struct epicsSpin {
|
||||
epicsMutexId lock;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
epicsSpin *spin;
|
||||
|
||||
spin = calloc(1, sizeof(*spin));
|
||||
if (!spin)
|
||||
goto fail;
|
||||
|
||||
spin->lock = epicsMutexCreate();
|
||||
if (!spin->lock)
|
||||
goto fail;
|
||||
|
||||
return spin;
|
||||
|
||||
fail:
|
||||
free(spin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if(!ret)
|
||||
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
epicsMutexDestroy(spin->lock);
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
epicsMutexLockStatus status;
|
||||
|
||||
status = epicsMutexLock(spin->lock);
|
||||
if (status != epicsMutexLockOK) {
|
||||
errlogPrintf("epicsSpinLock(%p): epicsMutexLock returned %s\n", spin,
|
||||
status == epicsMutexLockTimeout ?
|
||||
"epicsMutexLockTimeout" : "epicsMutexLockError");
|
||||
}
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
epicsMutexLockStatus status;
|
||||
|
||||
status = epicsMutexTryLock(spin->lock);
|
||||
if (status == epicsMutexLockOK) return 0;
|
||||
if (status == epicsMutexLockTimeout) return 1;
|
||||
|
||||
errlogPrintf("epicsSpinTryLock(%p): epicsMutexTryLock returned epicsMutexLockError\n", spin);
|
||||
return 2;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
epicsMutexUnlock(spin->lock);
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "osdMutex.h"
|
||||
|
||||
/* Until these can be demonstrated to work leave them undefined*/
|
||||
#undef _POSIX_THREAD_PROCESS_SHARED
|
||||
@@ -84,7 +85,7 @@ epicsShareFunc epicsEventId epicsShareAPI epicsEventCreate(epicsEventInitialStat
|
||||
int status;
|
||||
|
||||
pevent = callocMustSucceed(1,sizeof(*pevent),"epicsEventCreate");
|
||||
status = pthread_mutex_init(&pevent->mutex,0);
|
||||
status = epicsPosixMutexInit(&pevent->mutex,posixMutexDefault);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsEventCreate");
|
||||
status = pthread_cond_init(&pevent->cond,0);
|
||||
checkStatusQuit(status,"pthread_cond_init","epicsEventCreate");
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsMutex.h"
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "envDefs.h"
|
||||
|
||||
#define checkStatus(status,message) \
|
||||
if((status)) { \
|
||||
@@ -37,6 +38,101 @@ if(status) { \
|
||||
cantProceed((method)); \
|
||||
}
|
||||
|
||||
/* Until these can be demonstrated to work leave them undefined*/
|
||||
/* On solaris 8 _POSIX_THREAD_PRIO_INHERIT fails*/
|
||||
#if defined(DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
#undef _POSIX_THREAD_PRIO_INHERIT
|
||||
#endif
|
||||
|
||||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500
|
||||
#define HAVE_RECURSIVE_MUTEX
|
||||
#else
|
||||
#undef HAVE_RECURSIVE_MUTEX
|
||||
#endif
|
||||
|
||||
/* Global var - pthread_once does not support passing args but it is more efficient
|
||||
* then epicsThreadOnce which always acquires a mutex.
|
||||
*/
|
||||
static pthread_mutexattr_t globalAttrDefault;
|
||||
#ifdef HAVE_RECURSIVE_MUTEX
|
||||
static pthread_mutexattr_t globalAttrRecursive;
|
||||
#endif
|
||||
static pthread_once_t globalAttrInitOnce = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void setAttrDefaults(pthread_mutexattr_t *a)
|
||||
{
|
||||
int status;
|
||||
status = pthread_mutexattr_init(a);
|
||||
checkStatusQuit(status,"pthread_mutexattr_init","setAttrDefaults");
|
||||
|
||||
{
|
||||
const char *p = envGetConfigParamPtr(&EPICS_MUTEX_USE_PRIORITY_INHERITANCE);
|
||||
char c = p ? toupper(p[0]) : 'N';
|
||||
if ( 'T' == c || 'Y' == c || '1' == c ) {
|
||||
#if defined _POSIX_THREAD_PRIO_INHERIT
|
||||
status = pthread_mutexattr_setprotocol(a, PTHREAD_PRIO_INHERIT);
|
||||
if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocol(PTHREAD_PRIO_INHERIT)");
|
||||
#ifndef HAVE_RECURSIVE_MUTEX
|
||||
/* The implementation based on a condition variable below does not support
|
||||
* priority-inheritance!
|
||||
*/
|
||||
fprintf(stderr,"WARNING: PRIORITY-INHERITANCE UNAVAILABLE for epicsMutex\n");
|
||||
#endif
|
||||
#else
|
||||
fprintf(stderr,"WARNING: PRIORITY-INHERITANCE UNAVAILABLE OR NOT COMPILED IN\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void globalAttrInit()
|
||||
{
|
||||
int status;
|
||||
|
||||
setAttrDefaults( &globalAttrDefault );
|
||||
|
||||
#ifdef HAVE_RECURSIVE_MUTEX
|
||||
setAttrDefaults( &globalAttrRecursive );
|
||||
status = pthread_mutexattr_settype(&globalAttrRecursive, PTHREAD_MUTEX_RECURSIVE);
|
||||
checkStatusQuit(status, "pthread_mutexattr_settype(PTHREAD_MUTEX_RECURSIVE)", "globalAttrInit");
|
||||
#endif
|
||||
}
|
||||
|
||||
epicsShareFunc pthread_mutexattr_t * epicsShareAPI epicsPosixMutexAttrGet (EpicsPosixMutexProperty p)
|
||||
{
|
||||
int status;
|
||||
status = pthread_once( &globalAttrInitOnce, globalAttrInit );
|
||||
checkStatusQuit(status,"pthread_once","epicsPosixMutexAttrGet");
|
||||
switch ( p ) {
|
||||
default:
|
||||
case posixMutexDefault:
|
||||
break;
|
||||
case posixMutexRecursive:
|
||||
#ifdef HAVE_RECURSIVE_MUTEX
|
||||
return &globalAttrRecursive;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return &globalAttrDefault;
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsPosixMutexInit (pthread_mutex_t *m, EpicsPosixMutexProperty p)
|
||||
{
|
||||
pthread_mutexattr_t *atts = epicsPosixMutexAttrGet( p );
|
||||
if ( ! atts )
|
||||
return ENOTSUP;
|
||||
return pthread_mutex_init(m, atts);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsPosixMutexMustInit (pthread_mutex_t *m, EpicsPosixMutexProperty p)
|
||||
{
|
||||
int status;
|
||||
status = epicsPosixMutexInit(m, p);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsMustInitPosixMutex");
|
||||
}
|
||||
|
||||
static int mutexLock(pthread_mutex_t *id)
|
||||
{
|
||||
int status;
|
||||
@@ -47,11 +143,6 @@ static int mutexLock(pthread_mutex_t *id)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Until these can be demonstrated to work leave them undefined*/
|
||||
/* On solaris 8 _POSIX_THREAD_PRIO_INHERIT fails*/
|
||||
#undef _POSIX_THREAD_PROCESS_SHARED
|
||||
#undef _POSIX_THREAD_PRIO_INHERIT
|
||||
|
||||
/* Two completely different implementations are provided below
|
||||
* If support is available for PTHREAD_MUTEX_RECURSIVE then
|
||||
* only pthread_mutex is used.
|
||||
@@ -60,9 +151,8 @@ static int mutexLock(pthread_mutex_t *id)
|
||||
*/
|
||||
|
||||
|
||||
#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500
|
||||
#ifdef HAVE_RECURSIVE_MUTEX
|
||||
typedef struct epicsMutexOSD {
|
||||
pthread_mutexattr_t mutexAttr;
|
||||
pthread_mutex_t lock;
|
||||
} epicsMutexOSD;
|
||||
|
||||
@@ -71,20 +161,8 @@ epicsMutexOSD * epicsMutexOsdCreate(void) {
|
||||
int status;
|
||||
|
||||
pmutex = callocMustSucceed(1, sizeof(*pmutex), "epicsMutexOsdCreate");
|
||||
status = pthread_mutexattr_init(&pmutex->mutexAttr);
|
||||
checkStatusQuit(status,"pthread_mutexattr_init", "epicsMutexOsdCreate");
|
||||
|
||||
#if defined _POSIX_THREAD_PRIO_INHERIT
|
||||
status = pthread_mutexattr_setprotocol(&pmutex->mutexAttr,
|
||||
PTHREAD_PRIO_INHERIT);
|
||||
if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal");
|
||||
#endif /*_POSIX_THREAD_PRIO_INHERIT*/
|
||||
|
||||
status = pthread_mutexattr_settype(&pmutex->mutexAttr,
|
||||
PTHREAD_MUTEX_RECURSIVE);
|
||||
if (errVerbose) checkStatus(status, "pthread_mutexattr_settype");
|
||||
|
||||
status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr);
|
||||
status = epicsPosixMutexInit(&pmutex->lock, posixMutexRecursive);
|
||||
checkStatusQuit(status, "pthread_mutex_init", "epicsMutexOsdCreate");
|
||||
return pmutex;
|
||||
}
|
||||
@@ -95,8 +173,6 @@ void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex)
|
||||
|
||||
status = pthread_mutex_destroy(&pmutex->lock);
|
||||
checkStatus(status, "pthread_mutex_destroy");
|
||||
status = pthread_mutexattr_destroy(&pmutex->mutexAttr);
|
||||
checkStatus(status, "pthread_mutexattr_destroy");
|
||||
free(pmutex);
|
||||
}
|
||||
|
||||
@@ -135,15 +211,83 @@ void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level)
|
||||
{
|
||||
}
|
||||
|
||||
#else /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
|
||||
#else /* #ifdef HAVE_RECURSIVE_MUTEX */
|
||||
|
||||
/* The standard EPICS implementation of a recursive mutex (in absence of native support)
|
||||
* does not allow for priority-inheritance:
|
||||
* a low priority thread may hold the ('soft-') mutex, i.e., may be preempted in the
|
||||
* critical section without the high-priority thread noticing (because the HP-thread is
|
||||
* sleeping on the condvar and not waiting for the mutex).
|
||||
*
|
||||
* A better implementation could be:
|
||||
*
|
||||
* struct epicsMutexOSD {
|
||||
* pthread_mutex_t mtx;
|
||||
* atomic<pthread_t> owner;
|
||||
* unsigned count;
|
||||
* };
|
||||
*
|
||||
* void mutexLock(struct epicsMutexOSD *m)
|
||||
* {
|
||||
* pthread_t currentOwner = atomic_load(&m->owner, acquire);
|
||||
*
|
||||
* if ( pthread_equal(currentOwner, pthread_self()) ) {
|
||||
* m->count++;
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* pthread_mutex_lock(&m->mtx);
|
||||
* // ordering of this write to 'owner' is irrelevant since it doesn't matter
|
||||
* // if another thread performing the test above sees the 'invalid' or already
|
||||
* // 'our' TID.
|
||||
* atomic_store(&m->owner, pthread_self(), relaxed);
|
||||
* // 'count' is only ever accessed with 'mtx' held
|
||||
* m->count = 1;
|
||||
* }
|
||||
*
|
||||
* void mutexUnlock(struct epicsMutexOSD *o)
|
||||
* {
|
||||
* o->count--;
|
||||
* if ( o->count == 0 ) {
|
||||
* // acquire-release ordering between here and 'mutexLock' above'!
|
||||
* // Theoretically (but extremely unlikely) the executing thread
|
||||
* // may go away and a newly created thread with the same (recycled)
|
||||
* // TID on a different CPU could still see the old TID in mutexLock
|
||||
* // and believe it already owns the mutex...
|
||||
* atomic_store(&m->owner, invalid_thread_id, release);
|
||||
* pthread_mutex_unlock( &o->mtx );
|
||||
* }
|
||||
*
|
||||
* The 'invalid_thread_id' could be an ID of a permanently suspended dummy thread
|
||||
* (pthread does not define a 'NULL' ID and you don't want to get into an 'ABA'-sort
|
||||
* of situation where 'mutexLock' believes to be the current owner because the 'invalid'
|
||||
* ID is a 'recycled' thread id).
|
||||
*
|
||||
* Without atomic operations we'd have to introduce a second mutex to protect the 'owner'
|
||||
* member ('count' is only ever accessed with the mutex held). But that would then
|
||||
* lead to two extra lock/unlock pairs in 'mutexLock'. A dirty version would ignore that
|
||||
* and rely on pthread_t fitting in a CPU word and the acquire/release corner-case mentioned
|
||||
* above to never happen. Plus, some CPUs (x86) are more strongly (acq/rel) ordered implicitly.
|
||||
*
|
||||
* Here the corner case again:
|
||||
*
|
||||
* CPU1 CPU2
|
||||
* owner = 1234
|
||||
* ...
|
||||
* owner = invalid_tid
|
||||
* mutex_unlock()
|
||||
*
|
||||
* thread 1234 dies new thread with recycled TID 1234
|
||||
* enters osdMutexLock
|
||||
* 'owner=invalid_tid' assignment not yet visible on this CPU
|
||||
* if ( pthread_equal( owner, pthread_self() ) ) {
|
||||
* ==> ERRONEOUSLY ENTERS HERE
|
||||
* }
|
||||
*/
|
||||
|
||||
typedef struct epicsMutexOSD {
|
||||
pthread_mutexattr_t mutexAttr;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t waitToBeOwner;
|
||||
#if defined _POSIX_THREAD_PROCESS_SHARED
|
||||
pthread_condattr_t condAttr;
|
||||
#endif /*_POSIX_THREAD_PROCESS_SHARED*/
|
||||
int count;
|
||||
int owned; /* TRUE | FALSE */
|
||||
pthread_t ownerTid;
|
||||
@@ -154,28 +298,10 @@ epicsMutexOSD * epicsMutexOsdCreate(void) {
|
||||
int status;
|
||||
|
||||
pmutex = callocMustSucceed(1, sizeof(*pmutex), "epicsMutexOsdCreate");
|
||||
status = pthread_mutexattr_init(&pmutex->mutexAttr);
|
||||
checkStatusQuit(status, "pthread_mutexattr_init", "epicsMutexOsdCreate");
|
||||
|
||||
#if defined _POSIX_THREAD_PRIO_INHERIT
|
||||
status = pthread_mutexattr_setprotocol(
|
||||
&pmutex->mutexAttr,PTHREAD_PRIO_INHERIT);
|
||||
if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal");
|
||||
#endif /*_POSIX_THREAD_PRIO_INHERIT*/
|
||||
epicsPosixMutexMustInit(&pmutex->lock, posixMutexDefault);
|
||||
|
||||
status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr);
|
||||
checkStatusQuit(status, "pthread_mutex_init", "epicsMutexOsdCreate");
|
||||
|
||||
#if defined _POSIX_THREAD_PROCESS_SHARED
|
||||
status = pthread_condattr_init(&pmutex->condAttr);
|
||||
checkStatus(status, "pthread_condattr_init");
|
||||
status = pthread_condattr_setpshared(&pmutex->condAttr,
|
||||
PTHREAD_PROCESS_PRIVATE);
|
||||
checkStatus(status, "pthread_condattr_setpshared");
|
||||
status = pthread_cond_init(&pmutex->waitToBeOwner, &pmutex->condAttr);
|
||||
#else
|
||||
status = pthread_cond_init(&pmutex->waitToBeOwner, 0);
|
||||
#endif /*_POSIX_THREAD_PROCESS_SHARED*/
|
||||
checkStatusQuit(status, "pthread_cond_init", "epicsMutexOsdCreate");
|
||||
return pmutex;
|
||||
}
|
||||
@@ -186,13 +312,8 @@ void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex)
|
||||
|
||||
status = pthread_cond_destroy(&pmutex->waitToBeOwner);
|
||||
checkStatus(status, "pthread_cond_destroy");
|
||||
#if defined _POSIX_THREAD_PROCESS_SHARED
|
||||
status = pthread_condattr_destroy(&pmutex->condAttr);
|
||||
#endif /*_POSIX_THREAD_PROCESS_SHARED*/
|
||||
status = pthread_mutex_destroy(&pmutex->lock);
|
||||
checkStatus(status, "pthread_mutex_destroy");
|
||||
status = pthread_mutexattr_destroy(&pmutex->mutexAttr);
|
||||
checkStatus(status, "pthread_mutexattr_destroy");
|
||||
free(pmutex);
|
||||
}
|
||||
|
||||
@@ -281,4 +402,4 @@ void epicsMutexOsdShow(struct epicsMutexOSD *pmutex,unsigned int level)
|
||||
printf("ownerTid %p count %d owned %d\n",
|
||||
(void *)pmutex->ownerTid, pmutex->count, pmutex->owned);
|
||||
}
|
||||
#endif /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
|
||||
#endif /* #ifdef HAVE_RECURSIVE_MUTEX */
|
||||
|
||||
@@ -7,4 +7,26 @@
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* for a pure posix implementation no osdMutex.h definitions are needed*/
|
||||
#ifndef osdMutexh
|
||||
#define osdMutexh
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {posixMutexDefault = 0, posixMutexRecursive = 1} EpicsPosixMutexProperty;
|
||||
|
||||
/* Returns NULL if requested set of properties is not supported */
|
||||
epicsShareFunc pthread_mutexattr_t * epicsShareAPI epicsPosixMutexAttrGet (EpicsPosixMutexProperty);
|
||||
epicsShareFunc int epicsShareAPI epicsPosixMutexInit (pthread_mutex_t *,EpicsPosixMutexProperty);
|
||||
epicsShareFunc void epicsShareAPI epicsPosixMutexMustInit(pthread_mutex_t *,EpicsPosixMutexProperty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* osdMutexh */
|
||||
|
||||
182
src/libCom/osi/os/posix/osdSpin.c
Normal file
182
src/libCom/osi/os/posix/osdSpin.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "errlog.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
/* POSIX spinlocks may be subject to priority inversion
|
||||
* and so can't be guaranteed safe in situations where
|
||||
* threads have different priorities, and thread
|
||||
* preemption can't be disabled.
|
||||
*/
|
||||
#if defined(DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
#if defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS > 0)
|
||||
# define USE_PSPIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define checkStatus(status,message) \
|
||||
if ((status)) { \
|
||||
errlogPrintf("epicsSpin %s failed: error %s\n", \
|
||||
(message), strerror((status))); \
|
||||
}
|
||||
|
||||
#ifdef USE_PSPIN
|
||||
|
||||
/*
|
||||
* POSIX SPIN LOCKS IMPLEMENTATION
|
||||
*/
|
||||
|
||||
typedef struct epicsSpin {
|
||||
pthread_spinlock_t lock;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
epicsSpin *spin;
|
||||
int status;
|
||||
|
||||
spin = calloc(1, sizeof(*spin));
|
||||
if (!spin)
|
||||
goto fail;
|
||||
|
||||
status = pthread_spin_init(&spin->lock, PTHREAD_PROCESS_PRIVATE);
|
||||
checkStatus(status, "pthread_spin_init");
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
return spin;
|
||||
|
||||
fail:
|
||||
free(spin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_spin_destroy(&spin->lock);
|
||||
checkStatus(status, "pthread_spin_destroy");
|
||||
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_spin_lock(&spin->lock);
|
||||
checkStatus(status, "pthread_spin_lock");
|
||||
if (status)
|
||||
cantProceed(NULL);
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_spin_trylock(&spin->lock);
|
||||
if (status == EBUSY)
|
||||
return 1;
|
||||
checkStatus(status, "pthread_spin_trylock");
|
||||
return status;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_spin_unlock(&spin->lock);
|
||||
checkStatus(status, "pthread_spin_unlock");
|
||||
}
|
||||
|
||||
#else /* USE_PSPIN */
|
||||
|
||||
#include <osdMutex.h>
|
||||
|
||||
/*
|
||||
* POSIX MUTEX IMPLEMENTATION
|
||||
*/
|
||||
|
||||
typedef struct epicsSpin {
|
||||
pthread_mutex_t lock;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
epicsSpin *spin;
|
||||
int status;
|
||||
|
||||
spin = calloc(1, sizeof(*spin));
|
||||
if (!spin)
|
||||
goto fail;
|
||||
|
||||
status = epicsPosixMutexInit(&spin->lock, posixMutexDefault);
|
||||
checkStatus(status, "pthread_mutex_init");
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
return spin;
|
||||
|
||||
fail:
|
||||
free(spin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_destroy(&spin->lock);
|
||||
checkStatus(status, "pthread_mutex_destroy");
|
||||
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_lock(&spin->lock);
|
||||
checkStatus(status, "pthread_mutex_lock");
|
||||
if (status)
|
||||
cantProceed(NULL);
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_trylock(&spin->lock);
|
||||
if (status == EBUSY)
|
||||
return 1;
|
||||
checkStatus(status, "pthread_mutex_trylock");
|
||||
return status;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_unlock(&spin->lock);
|
||||
checkStatus(status, "pthread_mutex_unlock");
|
||||
}
|
||||
|
||||
#endif /* USE_PSPIN */
|
||||
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if(!ret)
|
||||
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
|
||||
return ret;
|
||||
}
|
||||
@@ -316,9 +316,9 @@ static void once(void)
|
||||
int status;
|
||||
|
||||
pthread_key_create(&getpthreadInfo,0);
|
||||
status = pthread_mutex_init(&onceLock,0);
|
||||
status = epicsPosixMutexInit(&onceLock,posixMutexDefault);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
|
||||
status = pthread_mutex_init(&listLock,0);
|
||||
status = epicsPosixMutexInit(&listLock,posixMutexDefault);
|
||||
checkStatusQuit(status,"pthread_mutex_init","epicsThreadInit");
|
||||
pcommonAttr = calloc(1,sizeof(commonAttr));
|
||||
if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit");
|
||||
|
||||
@@ -110,7 +110,22 @@ static long vxDevWriteProbe (unsigned wordSize, volatile void *ptr, const void *
|
||||
|
||||
static void *devA24Malloc(size_t size);
|
||||
static void devA24Free(void *pBlock);
|
||||
static long devInit(void) { return 0;}
|
||||
|
||||
|
||||
static int (*sysIntEnableFunc)(int) = NULL;
|
||||
static int (*sysIntDisableFunc)(int) = NULL;
|
||||
static int (*sysIntEnablePICFunc)(int) = NULL;
|
||||
static int (*sysIntDisablePICFunc)(int) = NULL;
|
||||
|
||||
static long devInit(void)
|
||||
{
|
||||
/* We don't know which functions are implemented in the BSP */
|
||||
sysIntEnableFunc = epicsFindSymbol ("sysIntEnable");
|
||||
sysIntDisableFunc = epicsFindSymbol ("sysIntDisable");
|
||||
sysIntDisablePICFunc = epicsFindSymbol ("sysIntDisablePIC");
|
||||
sysIntEnablePICFunc = epicsFindSymbol ("sysIntEnablePIC");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long vxDevConnectInterruptVME (
|
||||
unsigned vectorNumber,
|
||||
@@ -214,16 +229,8 @@ static long vxDevDisconnectInterruptVME (
|
||||
*/
|
||||
static long vxDevEnableInterruptLevelVME (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY != I80X86
|
||||
int s;
|
||||
s = sysIntEnable (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
if (!sysIntEnableFunc) return S_dev_intEnFail;
|
||||
return sysIntEnableFunc (level) == OK ? 0 : S_dev_intEnFail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -231,16 +238,8 @@ static long vxDevEnableInterruptLevelVME (unsigned level)
|
||||
*/
|
||||
long devEnableInterruptLevelISA (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY == I80X86
|
||||
int s;
|
||||
s = sysIntEnablePIC (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
if (!sysIntEnablePICFunc) return S_dev_intEnFail;
|
||||
return sysIntEnablePICFunc (level) == OK ? 0 : S_dev_intEnFail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -248,17 +247,8 @@ long devEnableInterruptLevelISA (unsigned level)
|
||||
*/
|
||||
long devDisableInterruptLevelISA (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY == I80X86
|
||||
int s;
|
||||
s = sysIntDisablePIC (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
|
||||
return 0;
|
||||
if (!sysIntDisablePICFunc) return S_dev_intDissFail;
|
||||
return sysIntDisablePICFunc (level) == OK ? 0 : S_dev_intDissFail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -266,16 +256,8 @@ long devDisableInterruptLevelISA (unsigned level)
|
||||
*/
|
||||
static long vxDevDisableInterruptLevelVME (unsigned level)
|
||||
{
|
||||
# if CPU_FAMILY != I80X86
|
||||
int s;
|
||||
s = sysIntDisable (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intDissFail;
|
||||
}
|
||||
return 0;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
if (!sysIntDisableFunc) return S_dev_intDissFail;
|
||||
return sysIntDisableFunc (level) == OK ? 0 : S_dev_intDissFail;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
115
src/libCom/osi/os/vxWorks/osdSpin.c
Normal file
115
src/libCom/osi/os/vxWorks/osdSpin.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2012 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* Copyright (c) 2013 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2013 Brookhaven Science Assoc. as Operator of Brookhaven
|
||||
* National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Authors: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
* Andrew Johnson <anj@aps.anl.gov>
|
||||
* Michael Davidsaver <mdavidsaver@bnl.gov>
|
||||
*
|
||||
* Inspired by Linux UP spinlocks implemention
|
||||
* include/linux/spinlock_api_up.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* vxWorks (single CPU): LOCK INTERRUPT and DISABLE PREEMPTION
|
||||
*
|
||||
* CAVEAT:
|
||||
* This implementation will not compile on vxWorks SMP architectures.
|
||||
* These architectures provide spinlocks, which must be used instead.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is needed for vxWorks 6.x to prevent an obnoxious compiler warning */
|
||||
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <intLib.h>
|
||||
#include <logLib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include "cantProceed.h"
|
||||
#include "epicsSpin.h"
|
||||
|
||||
typedef struct epicsSpin {
|
||||
int key;
|
||||
unsigned int locked;
|
||||
} epicsSpin;
|
||||
|
||||
epicsSpinId epicsSpinCreate(void) {
|
||||
return calloc(1, sizeof(epicsSpin));
|
||||
}
|
||||
|
||||
epicsSpinId epicsSpinMustCreate(void)
|
||||
{
|
||||
epicsSpinId ret = epicsSpinCreate();
|
||||
if (!ret)
|
||||
cantProceed("epicsSpinMustCreate: epicsSpinCreate failed.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void epicsSpinDestroy(epicsSpinId spin) {
|
||||
free(spin);
|
||||
}
|
||||
|
||||
void epicsSpinLock(epicsSpinId spin) {
|
||||
int key = intLock();
|
||||
|
||||
if (!intContext())
|
||||
taskLock();
|
||||
if (spin->locked) {
|
||||
intUnlock(key);
|
||||
if (!intContext()) {
|
||||
taskUnlock();
|
||||
logMsg("epicsSpinLock(%p): Deadlock.\n",
|
||||
(int) spin, 0, 0, 0, 0, 0);
|
||||
cantProceed("Recursive lock, missed unlock or block when locked.");
|
||||
}
|
||||
else {
|
||||
logMsg("epicsSpinLock(%p): Deadlock in ISR.\n"
|
||||
"Recursive lock, missed unlock or block when locked.\n",
|
||||
(int) spin, 0, 0, 0, 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
spin->key = key;
|
||||
spin->locked = 1;
|
||||
}
|
||||
|
||||
int epicsSpinTryLock(epicsSpinId spin) {
|
||||
int key = intLock();
|
||||
|
||||
if (!intContext())
|
||||
taskLock();
|
||||
if (spin->locked) {
|
||||
intUnlock(key);
|
||||
if (!intContext())
|
||||
taskUnlock();
|
||||
return 1;
|
||||
}
|
||||
spin->key = key;
|
||||
spin->locked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void epicsSpinUnlock(epicsSpinId spin) {
|
||||
int key = spin->key;
|
||||
|
||||
if (!spin->locked) {
|
||||
logMsg("epicsSpinUnlock(%p): not locked\n",
|
||||
(int) spin, 0, 0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
spin->key = spin->locked = 0;
|
||||
intUnlock(key);
|
||||
if (!intContext())
|
||||
taskUnlock();
|
||||
}
|
||||
@@ -177,6 +177,19 @@ static void NTPTimeSync(void *dummy)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ntpDelta > 10 * NTPTimeSyncInterval && NTPTimePvt.synchronized) {
|
||||
char nowTimeText[32];
|
||||
char syncTimeText[32];
|
||||
epicsTimeToStrftime(syncTimeText,sizeof(syncTimeText),"%Y-%m-%d %H:%M:%S.%09f",
|
||||
&NTPTimePvt.syncTime);
|
||||
epicsTimeToStrftime(nowTimeText,sizeof(nowTimeText),"%Y-%m-%d %H:%M:%S.%09f",
|
||||
&timeNow);
|
||||
errlogPrintf("NTPTimeSync: refuse to jump from %s to future %s (timespec: %li.%09li)\n",
|
||||
syncTimeText, nowTimeText, timespecNow.tv_sec, timespecNow.tv_nsec);
|
||||
NTPTimePvt.synchronized = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
NTPTimePvt.syncsFailed = 0;
|
||||
if (!NTPTimePvt.synchronized) {
|
||||
errlogPrintf("NTPTimeSync: Sync recovered.\n");
|
||||
@@ -274,6 +287,8 @@ int NTPTime_Report(int level)
|
||||
osdTickRateGet());
|
||||
printf("Measured tick rate = %.3f Hz\n",
|
||||
NTPTimePvt.tickRate);
|
||||
printf("Ticks to skip = %d ticks\n",
|
||||
NTPTimePvt.ticksToSkip);
|
||||
osdNTPReport();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* epicsRingBytes.cd */
|
||||
|
||||
/* Author: Eric Norum & Marty Kraimer Date: 15JUL99 */
|
||||
/*
|
||||
* Author: Marty Kraimer Date: 15JUL99
|
||||
* Eric Norum
|
||||
* Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -18,8 +21,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsSpin.h"
|
||||
#include "dbDefs.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsRingBytes.h"
|
||||
|
||||
/*
|
||||
@@ -31,26 +34,40 @@
|
||||
#define SLOP 16
|
||||
|
||||
typedef struct ringPvt {
|
||||
epicsSpinId lock;
|
||||
volatile int nextPut;
|
||||
volatile int nextGet;
|
||||
int size;
|
||||
volatile char *buffer;
|
||||
int highWaterMark;
|
||||
volatile char buffer[1]; /* actually larger */
|
||||
}ringPvt;
|
||||
|
||||
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int size)
|
||||
{
|
||||
ringPvt *pring = mallocMustSucceed(sizeof(ringPvt),"epicsRingBytesCreate");
|
||||
ringPvt *pring = malloc(sizeof(ringPvt) + size + SLOP);
|
||||
if(!pring)
|
||||
return NULL;
|
||||
pring->size = size + SLOP;
|
||||
pring->buffer = mallocMustSucceed(pring->size,"ringCreate");
|
||||
pring->highWaterMark = 0;
|
||||
pring->nextGet = 0;
|
||||
pring->nextPut = 0;
|
||||
pring->lock = 0;
|
||||
return((void *)pring);
|
||||
}
|
||||
|
||||
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesLockedCreate(int size)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)epicsRingBytesCreate(size);
|
||||
if(!pring)
|
||||
return NULL;
|
||||
pring->lock = epicsSpinCreate();
|
||||
return((void *)pring);
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsRingBytesDelete(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
free((void *)pring->buffer);
|
||||
if (pring->lock) epicsSpinDestroy(pring->lock);
|
||||
free((void *)pring);
|
||||
}
|
||||
|
||||
@@ -58,11 +75,14 @@ epicsShareFunc int epicsShareAPI epicsRingBytesGet(
|
||||
epicsRingBytesId id, char *value,int nbytes)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int nextGet = pring->nextGet;
|
||||
int nextPut = pring->nextPut;
|
||||
int size = pring->size;
|
||||
int nextGet, nextPut, size;
|
||||
int count;
|
||||
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
nextGet = pring->nextGet;
|
||||
nextPut = pring->nextPut;
|
||||
size = pring->size;
|
||||
|
||||
if (nextGet <= nextPut) {
|
||||
count = nextPut - nextGet;
|
||||
if (count < nbytes)
|
||||
@@ -90,6 +110,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesGet(
|
||||
}
|
||||
}
|
||||
pring->nextGet = nextGet;
|
||||
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
@@ -97,27 +119,36 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
|
||||
epicsRingBytesId id, char *value,int nbytes)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int nextGet = pring->nextGet;
|
||||
int nextPut = pring->nextPut;
|
||||
int size = pring->size;
|
||||
int freeCount, copyCount, topCount;
|
||||
int nextGet, nextPut, size;
|
||||
int freeCount, copyCount, topCount, used;
|
||||
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
nextGet = pring->nextGet;
|
||||
nextPut = pring->nextPut;
|
||||
size = pring->size;
|
||||
|
||||
if (nextPut < nextGet) {
|
||||
freeCount = nextGet - nextPut - SLOP;
|
||||
if (nbytes > freeCount)
|
||||
if (nbytes > freeCount) {
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
return 0;
|
||||
if (nbytes)
|
||||
}
|
||||
if (nbytes) {
|
||||
memcpy ((void *)&pring->buffer[nextPut], value, nbytes);
|
||||
}
|
||||
nextPut += nbytes;
|
||||
}
|
||||
else {
|
||||
freeCount = size - nextPut + nextGet - SLOP;
|
||||
if (nbytes > freeCount)
|
||||
if (nbytes > freeCount) {
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
return 0;
|
||||
}
|
||||
topCount = size - nextPut;
|
||||
copyCount = (nbytes > topCount) ? topCount : nbytes;
|
||||
if (copyCount)
|
||||
if (copyCount) {
|
||||
memcpy ((void *)&pring->buffer[nextPut], value, copyCount);
|
||||
}
|
||||
nextPut += copyCount;
|
||||
if (nextPut == size) {
|
||||
int nLeft = nbytes - copyCount;
|
||||
@@ -127,6 +158,12 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
|
||||
}
|
||||
}
|
||||
pring->nextPut = nextPut;
|
||||
|
||||
used = nextPut - nextGet;
|
||||
if (used < 0) used += pring->size;
|
||||
if (used > pring->highWaterMark) pring->highWaterMark = used;
|
||||
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
@@ -134,14 +171,20 @@ epicsShareFunc void epicsShareAPI epicsRingBytesFlush(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
pring->nextGet = pring->nextPut;
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesFreeBytes(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int nextGet = pring->nextGet;
|
||||
int nextPut = pring->nextPut;
|
||||
int nextGet, nextPut;
|
||||
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
nextGet = pring->nextGet;
|
||||
nextPut = pring->nextPut;
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
|
||||
if (nextPut < nextGet)
|
||||
return nextGet - nextPut - SLOP;
|
||||
@@ -152,8 +195,18 @@ epicsShareFunc int epicsShareAPI epicsRingBytesFreeBytes(epicsRingBytesId id)
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesUsedBytes(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int nextGet, nextPut;
|
||||
int used;
|
||||
|
||||
return pring->size - epicsRingBytesFreeBytes(id) - SLOP;
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
nextGet = pring->nextGet;
|
||||
nextPut = pring->nextPut;
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
|
||||
used = nextPut - nextGet;
|
||||
if (used < 0) used += pring->size;
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id)
|
||||
@@ -166,11 +219,33 @@ epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id)
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesIsEmpty(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int isEmpty;
|
||||
|
||||
return (pring->nextPut == pring->nextGet);
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
isEmpty = (pring->nextPut == pring->nextGet);
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id)
|
||||
{
|
||||
return (epicsRingBytesFreeBytes(id) <= 0);
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
return pring->highWaterMark;
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id)
|
||||
{
|
||||
ringPvt *pring = (ringPvt *)id;
|
||||
int used;
|
||||
if (pring->lock) epicsSpinLock(pring->lock);
|
||||
used = pring->nextGet - pring->nextPut;
|
||||
if (used < 0) used += pring->size;
|
||||
pring->highWaterMark = used;
|
||||
if (pring->lock) epicsSpinUnlock(pring->lock);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*epicsRingBytes.h */
|
||||
|
||||
/* Author: Eric Norum & Marty Kraimer Date: 15JUL99 */
|
||||
/*
|
||||
* Author: Marty Kraimer Date: 15JUL99
|
||||
* Eric Norum
|
||||
* Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef INCepicsRingBytesh
|
||||
#define INCepicsRingBytesh
|
||||
@@ -21,8 +24,11 @@ extern "C" {
|
||||
#include "shareLib.h"
|
||||
|
||||
typedef void *epicsRingBytesId;
|
||||
typedef void const *epicsRingBytesIdConst;
|
||||
|
||||
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int nbytes);
|
||||
/* Same, but secured by a spinlock */
|
||||
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesLockedCreate(int nbytes);
|
||||
epicsShareFunc void epicsShareAPI epicsRingBytesDelete(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesGet(
|
||||
epicsRingBytesId id, char *value,int nbytes);
|
||||
@@ -34,6 +40,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesUsedBytes(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesIsEmpty(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id);
|
||||
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -42,6 +50,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id);
|
||||
/* NOTES
|
||||
If there is only one writer it is not necessary to lock for put
|
||||
If there is a single reader it is not necessary to lock for puts
|
||||
|
||||
epicsRingBytesLocked uses a spinlock.
|
||||
*/
|
||||
|
||||
#endif /* INCepicsRingBytesh */
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*epicsRingPointer.cpp*/
|
||||
/* Author: Marty Kraimer Date: 13OCT2000 */
|
||||
|
||||
/*
|
||||
* Author: Marty Kraimer Date: 13OCT2000
|
||||
* Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -22,7 +27,13 @@ typedef epicsRingPointer<void> voidPointer;
|
||||
|
||||
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size)
|
||||
{
|
||||
voidPointer *pvoidPointer = new voidPointer(size);
|
||||
voidPointer *pvoidPointer = new voidPointer(size, false);
|
||||
return(reinterpret_cast<void *>(pvoidPointer));
|
||||
}
|
||||
|
||||
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerLockedCreate(int size)
|
||||
{
|
||||
voidPointer *pvoidPointer = new voidPointer(size, true);
|
||||
return(reinterpret_cast<void *>(pvoidPointer));
|
||||
}
|
||||
|
||||
@@ -79,3 +90,15 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id)
|
||||
voidPointer *pvoidPointer = reinterpret_cast<voidPointer*>(id);
|
||||
return((pvoidPointer->isFull()) ? 1 : 0);
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id)
|
||||
{
|
||||
voidPointer const *pvoidPointer = reinterpret_cast<voidPointer const*>(id);
|
||||
return(pvoidPointer->getHighWaterMark());
|
||||
}
|
||||
|
||||
epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id)
|
||||
{
|
||||
voidPointer *pvoidPointer = reinterpret_cast<voidPointer*>(id);
|
||||
pvoidPointer->resetHighWaterMark();
|
||||
}
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* Copyright (c) 2012 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*epicsRingPointer.h */
|
||||
|
||||
/* Author: Marty Kraimer Date: 15JUL99 */
|
||||
/*
|
||||
* Author: Marty Kraimer Date: 15JUL99
|
||||
* Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef INCepicsRingPointerh
|
||||
#define INCepicsRingPointerh
|
||||
@@ -16,15 +19,18 @@
|
||||
/* NOTES
|
||||
* If there is only one writer it is not necessary to lock push
|
||||
* If there is a single reader it is not necessary to lock pop
|
||||
*
|
||||
* epicsRingPointerLocked uses a spinlock.
|
||||
*/
|
||||
|
||||
#include "epicsSpin.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
template <class T>
|
||||
class epicsRingPointer {
|
||||
public: /* Functions */
|
||||
epicsRingPointer(int size);
|
||||
epicsRingPointer(int size, bool locked);
|
||||
~epicsRingPointer();
|
||||
bool push(T *p);
|
||||
T* pop();
|
||||
@@ -34,17 +40,22 @@ public: /* Functions */
|
||||
int getSize() const;
|
||||
bool isEmpty() const;
|
||||
bool isFull() const;
|
||||
int getHighWaterMark() const;
|
||||
void resetHighWaterMark();
|
||||
|
||||
private: /* Prevent compiler-generated member functions */
|
||||
/* default constructor, copy constructor, assignment operator */
|
||||
epicsRingPointer();
|
||||
epicsRingPointer(const epicsRingPointer &);
|
||||
epicsRingPointer& operator=(const epicsRingPointer &);
|
||||
int getUsedNoLock() const;
|
||||
|
||||
private: /* Data */
|
||||
epicsSpinId lock;
|
||||
volatile int nextPush;
|
||||
volatile int nextPop;
|
||||
int size;
|
||||
int highWaterMark;
|
||||
T * volatile * buffer;
|
||||
};
|
||||
|
||||
@@ -52,8 +63,11 @@ extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
typedef void *epicsRingPointerId;
|
||||
typedef void const *epicsRingPointerIdConst;
|
||||
|
||||
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size);
|
||||
/* Same, but secured by a spinlock */
|
||||
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerLockedCreate(int size);
|
||||
epicsShareFunc void epicsShareAPI epicsRingPointerDelete(epicsRingPointerId id);
|
||||
/*ringPointerPush returns (0,1) if p (was not, was) put on ring*/
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerPush(epicsRingPointerId id,void *p);
|
||||
@@ -65,6 +79,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerGetUsed(epicsRingPointerId id)
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerGetSize(epicsRingPointerId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerIsEmpty(epicsRingPointerId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
|
||||
epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id);
|
||||
epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id);
|
||||
|
||||
/* This routine was incorrectly named in previous releases */
|
||||
#define epicsRingPointerSize epicsRingPointerGetSize
|
||||
@@ -85,75 +101,132 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
|
||||
#ifdef __cplusplus
|
||||
|
||||
template <class T>
|
||||
inline epicsRingPointer<T>::epicsRingPointer(int sz) :
|
||||
nextPush(0), nextPop(0), size(sz+1), buffer(new T* [sz+1]) {}
|
||||
inline epicsRingPointer<T>::epicsRingPointer(int sz, bool locked) :
|
||||
lock(0), nextPush(0), nextPop(0), size(sz+1), highWaterMark(0),
|
||||
buffer(new T* [sz+1])
|
||||
{
|
||||
if (locked)
|
||||
lock = epicsSpinCreate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline epicsRingPointer<T>::~epicsRingPointer()
|
||||
{ delete [] buffer;}
|
||||
{
|
||||
if (lock) epicsSpinDestroy(lock);
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool epicsRingPointer<T>::push(T *p)
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
int next = nextPush;
|
||||
int newNext = next + 1;
|
||||
if(newNext>=size) newNext=0;
|
||||
if(newNext==nextPop) return(false);
|
||||
if (newNext == nextPop) {
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return(false);
|
||||
}
|
||||
buffer[next] = p;
|
||||
nextPush = newNext;
|
||||
int used = getUsedNoLock();
|
||||
if (used > highWaterMark) highWaterMark = used;
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return(true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T* epicsRingPointer<T>::pop()
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
int next = nextPop;
|
||||
if(next == nextPush) return(0);
|
||||
if (next == nextPush) {
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return(0);
|
||||
}
|
||||
T*p = buffer[next];
|
||||
++next;
|
||||
if(next >=size) next = 0;
|
||||
nextPop = next;
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return(p);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void epicsRingPointer<T>::flush()
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
nextPop = 0;
|
||||
nextPush = 0;
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getFree() const
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
int n = nextPop - nextPush - 1;
|
||||
if (n < 0) n += size;
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getUsed() const
|
||||
inline int epicsRingPointer<T>::getUsedNoLock() const
|
||||
{
|
||||
int n = nextPush - nextPop;
|
||||
if (n < 0) n += size;
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getUsed() const
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
int n = getUsedNoLock();
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return n;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getSize() const
|
||||
{ return(size-1);}
|
||||
{
|
||||
return(size-1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool epicsRingPointer<T>::isEmpty() const
|
||||
{ return(nextPush==nextPop);}
|
||||
{
|
||||
bool isEmpty;
|
||||
if (lock) epicsSpinLock(lock);
|
||||
isEmpty = (nextPush == nextPop);
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool epicsRingPointer<T>::isFull() const
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
int count = nextPush - nextPop +1;
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
return((count == 0) || (count == size));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int epicsRingPointer<T>::getHighWaterMark() const
|
||||
{
|
||||
return highWaterMark;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void epicsRingPointer<T>::resetHighWaterMark()
|
||||
{
|
||||
if (lock) epicsSpinLock(lock);
|
||||
highWaterMark = getUsedNoLock();
|
||||
if (lock) epicsSpinUnlock(lock);
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* INCepicsRingPointerh */
|
||||
|
||||
@@ -197,5 +197,10 @@ TESTPROD_HOST += cvtFastPerform
|
||||
cvtFastPerform_SRCS += cvtFastPerform.cpp
|
||||
testHarness_SRCS += cvtFastPerform.cpp
|
||||
|
||||
TESTPROD_HOST_Linux += epicsMutexPriorityInversionTest
|
||||
epicsMutexPriorityInversionTest_SRCS += epicsMutexPriorityInversionTest.c
|
||||
epicsMutexPriorityInversionTest_SYS_LIBS_Linux += pthread rt
|
||||
TESTSCRIPTS_HOST_Linux+=epicsMutexPriorityInversionTest.t
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
266
src/libCom/test/epicsMutexPriorityInversionTest.c
Normal file
266
src/libCom/test/epicsMutexPriorityInversionTest.c
Normal file
@@ -0,0 +1,266 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <features.h>
|
||||
#include <sched.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsUnitTest.h>
|
||||
#include <errlog.h>
|
||||
#include <testMain.h>
|
||||
#include <time.h>
|
||||
#include <envDefs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define THE_CPU 0
|
||||
|
||||
#define SPIN_SECS 3000000
|
||||
|
||||
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,4)
|
||||
#define HAVE_CPU_AFFINITY
|
||||
#else
|
||||
#undef HAVE_CPU_AFFINITY
|
||||
#endif
|
||||
|
||||
typedef struct ThreadArg_ {
|
||||
epicsEventId sync;
|
||||
epicsEventId done;
|
||||
epicsMutexId mtx;
|
||||
volatile unsigned long end;
|
||||
unsigned long lim;
|
||||
int pri[3];
|
||||
} ThreadArg;
|
||||
|
||||
static unsigned long getClockUs()
|
||||
{
|
||||
struct timespec now;
|
||||
if ( clock_gettime( CLOCK_MONOTONIC, &now ) ) {
|
||||
testAbort("clock_gettime(CLOCK_MONOTONIC) failed");
|
||||
}
|
||||
return ((unsigned long)now.tv_sec)*1000000 + ((unsigned long)now.tv_nsec)/1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set affinity of executing thread to 'cpu'
|
||||
*/
|
||||
static void setThreadAffinity(int cpu)
|
||||
{
|
||||
#ifdef HAVE_CPU_AFFINITY
|
||||
cpu_set_t cset;
|
||||
|
||||
CPU_ZERO( &cset );
|
||||
CPU_SET( cpu, &cset );
|
||||
testOk1 ( 0 == pthread_setaffinity_np( pthread_self(), sizeof(cset), &cset ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure only 'cpu' is set in executing thread's affinity mask
|
||||
*/
|
||||
static void checkAffinity(int cpu)
|
||||
{
|
||||
#ifdef HAVE_CPU_AFFINITY
|
||||
cpu_set_t cset;
|
||||
|
||||
if ( pthread_getaffinity_np( pthread_self(), sizeof(cset), &cset) ) {
|
||||
testFail("pthread_getaffinity_np FAILED");
|
||||
return;
|
||||
}
|
||||
testOk ( 1 == CPU_COUNT( &cset ) && CPU_ISSET( cpu, &cset ), "Checking CPU affinity mask" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make sure executing thread uses SCHED_FIFO and
|
||||
* store its priority a->pri[idx]
|
||||
*
|
||||
* RETURNS: 0 if SCHED_FIFO engaged, nonzero otherwise.
|
||||
*/
|
||||
static int checkThreadPri(ThreadArg *a, unsigned idx)
|
||||
{
|
||||
int pol;
|
||||
struct sched_param p;
|
||||
if ( pthread_getschedparam( pthread_self(), &pol, &p ) ) {
|
||||
testFail("pthread_getschedparam FAILED");
|
||||
return 1;
|
||||
}
|
||||
if ( a && idx < sizeof(a->pri)/sizeof(a->pri[0]) ) {
|
||||
a->pri[idx] = p.sched_priority;
|
||||
}
|
||||
testOk1( SCHED_FIFO == pol );
|
||||
return (SCHED_FIFO != pol);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Low-priority thread.
|
||||
*
|
||||
* Lock mutex and signal to the medium-priority thread
|
||||
* that it may proceed.
|
||||
*
|
||||
* Since all three (high-, medium- and low-priority threads)
|
||||
* execute on the same CPU (via affinity) the medium-
|
||||
* priority thread will then take over the CPU and prevent
|
||||
* (unless priority-inheritance is enabled, that is)
|
||||
* the low-priority thread from continueing on to unlock
|
||||
* the mutex.
|
||||
*/
|
||||
static void loPriThread(void *parm)
|
||||
{
|
||||
ThreadArg *a = (ThreadArg*)parm;
|
||||
|
||||
checkAffinity( THE_CPU );
|
||||
|
||||
checkThreadPri( a, 0 );
|
||||
|
||||
epicsMutexMustLock( a->mtx );
|
||||
|
||||
epicsEventSignal( a->sync );
|
||||
|
||||
/* medium-priority thread takes over CPU and spins
|
||||
* while the high-priority thread waits for the mutex.
|
||||
* With priority-inheritance enabled this thread's
|
||||
* priority will be increased so that the medium-
|
||||
* priority thread can be preempted and we proceed
|
||||
* to release the mutex.
|
||||
*/
|
||||
|
||||
epicsMutexUnlock( a->mtx );
|
||||
}
|
||||
|
||||
static void hiPriThread(void *parm)
|
||||
{
|
||||
ThreadArg *a = (ThreadArg*)parm;
|
||||
|
||||
/* Try to get the mutex */
|
||||
epicsMutexMustLock( a->mtx );
|
||||
/* Record the time when we obtained the mutex */
|
||||
a->end = getClockUs();
|
||||
epicsMutexUnlock( a->mtx );
|
||||
/* Tell the main thread that the test done */
|
||||
epicsEventSignal( a->done );
|
||||
}
|
||||
|
||||
static void miPriThread(void *parm)
|
||||
{
|
||||
ThreadArg *a = (ThreadArg*)parm;
|
||||
|
||||
/* Basic checks:
|
||||
* - affinity must be set to use single CPU for all threads
|
||||
* - SCHED_FIFO must be in effect
|
||||
*/
|
||||
checkAffinity( THE_CPU );
|
||||
checkThreadPri( a, 1 );
|
||||
|
||||
/* Create the low-priority thread. */
|
||||
epicsThreadMustCreate("testLo",
|
||||
a->pri[0],
|
||||
epicsThreadGetStackSize( epicsThreadStackMedium ),
|
||||
loPriThread,
|
||||
a);
|
||||
|
||||
/* Wait until low-priority thread has taken the mutex */
|
||||
epicsEventMustWait( a->sync );
|
||||
|
||||
/* Compute the end-time for our spinning loop */
|
||||
a->lim = getClockUs() + SPIN_SECS;
|
||||
a->end = 0;
|
||||
|
||||
/* Create the high-priority thread. The hiPri thread will
|
||||
* block for the mutex and
|
||||
* if priority-inheritance is available:
|
||||
* increase the low-priority thread's priority temporarily
|
||||
* so it can proceed to release the mutex and hand it to
|
||||
* the high-priority thread.
|
||||
* if priority-inheritance is not available:
|
||||
* the high-priority thread will have to wait until we are
|
||||
* done spinning and the low-priority thread is scheduled
|
||||
* again.
|
||||
*/
|
||||
epicsThreadMustCreate("testHi",
|
||||
a->pri[2],
|
||||
epicsThreadGetStackSize( epicsThreadStackMedium ),
|
||||
hiPriThread,
|
||||
a);
|
||||
|
||||
/* Spin for some time; the goal is hogging the CPU and thus preventing
|
||||
* the low-priority thread from being scheduled.
|
||||
* If priority-inheritance is enabled then the low-priority thread's
|
||||
* priority is temporarily increased so that we can be preempted. This
|
||||
* then causes the high-priority thread to record the 'end' time which
|
||||
* tells us that we can terminate early...
|
||||
*/
|
||||
while ( 0 == a->end && getClockUs() < a->lim )
|
||||
/* spin */;
|
||||
|
||||
/* w/o priority-inheritance the low-priority thread may proceed at
|
||||
* this point and release the mutex to the high-priority thread.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
#define NUM_TESTS 8
|
||||
|
||||
MAIN(epicsMutexPriorityInversionTest)
|
||||
{
|
||||
ThreadArg a;
|
||||
long hiPriStalledTimeUs;
|
||||
struct sched_param p_pri;
|
||||
|
||||
/* This happens too late - i.e., after initialization of libCom
|
||||
* user must set in the environment...
|
||||
epicsEnvSet("EPICS_MUTEX_USE_PRIORITY_INHERITANCE","YES");
|
||||
*/
|
||||
|
||||
a.mtx = epicsMutexMustCreate();
|
||||
a.sync = epicsEventMustCreate( epicsEventEmpty );
|
||||
a.done = epicsEventMustCreate( epicsEventEmpty );
|
||||
a.pri[0] = epicsThreadPriorityLow;
|
||||
a.pri[1] = epicsThreadPriorityMedium;
|
||||
a.pri[2] = epicsThreadPriorityHigh;
|
||||
|
||||
testPlan(NUM_TESTS);
|
||||
|
||||
#ifndef HAVE_CPU_AFFINITY
|
||||
#warning "glibc too old for this test: pthread_setaffinity_np() not available..."
|
||||
testSkip( NUM_TESTS, "glibc too old for this test: pthread_setaffinity_np() not implemented!" );
|
||||
return testDone();
|
||||
#endif
|
||||
|
||||
p_pri.sched_priority = sched_get_priority_min( SCHED_FIFO );
|
||||
if ( sched_setscheduler( 0, SCHED_FIFO, &p_pri ) ) {
|
||||
testDiag("SCHED_FIFO not engaged - maybe you need to be root to run this test?");
|
||||
testFail("sched_setscheduler(SCHED_FIFO)");
|
||||
testSkip( NUM_TESTS - 1, "SCHED_FIFO not engaged" );
|
||||
return testDone();
|
||||
} else {
|
||||
testPass("SCHED_FIFO can be used");
|
||||
}
|
||||
|
||||
setThreadAffinity( THE_CPU );
|
||||
/* created threads should inherit CPU affinity mask */
|
||||
|
||||
epicsThreadMustCreate("testMi",
|
||||
a.pri[1],
|
||||
epicsThreadGetStackSize( epicsThreadStackMedium ),
|
||||
miPriThread,
|
||||
&a);
|
||||
|
||||
epicsEventMustWait( a.done );
|
||||
|
||||
testOk1( (a.pri[0] < a.pri[1]) && (a.pri[1] < a.pri[2]) );
|
||||
|
||||
hiPriStalledTimeUs = a.end - (a.lim - SPIN_SECS);
|
||||
|
||||
testDiag("High-priority thread stalled for %li us\n", hiPriStalledTimeUs);
|
||||
testOk1( hiPriStalledTimeUs < 200 );
|
||||
|
||||
epicsEventDestroy( a.done );
|
||||
epicsEventDestroy( a.sync );
|
||||
epicsMutexDestroy( a.mtx );
|
||||
|
||||
return testDone();
|
||||
}
|
||||
10
src/libCom/test/epicsMutexPriorityInversionTest.plt
Normal file
10
src/libCom/test/epicsMutexPriorityInversionTest.plt
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
my $prog = "./$0";
|
||||
$prog =~ s/\.t$//;
|
||||
|
||||
$ENV{EPICS_MUTEX_USE_PRIORITY_INHERITANCE} = "YES";
|
||||
|
||||
$ENV{HARNESS_ACTIVE} = 1 if scalar @ARGV && shift eq '-tap';
|
||||
exec "$prog" or die "Can't run $prog: $!\n";
|
||||
@@ -49,6 +49,7 @@ variable(CASDEBUG,int)
|
||||
# dbStaticLib settings
|
||||
variable(dbRecordsOnceOnly,int)
|
||||
variable(dbBptNotMonotonic,int)
|
||||
variable(dbQuietMacroWarnings,int)
|
||||
|
||||
# dbLoadTemplate settings
|
||||
variable(dbTemplateMaxVars,int)
|
||||
|
||||
@@ -176,7 +176,7 @@ recordtype(ai) {
|
||||
pp(TRUE)
|
||||
interest(2)
|
||||
}
|
||||
field(ROFF,DBF_ULONG) {
|
||||
field(ROFF,DBF_LONG) {
|
||||
prompt("Raw Offset")
|
||||
pp(TRUE)
|
||||
interest(2)
|
||||
|
||||
@@ -82,7 +82,7 @@ recordtype(ao) {
|
||||
interest(1)
|
||||
size(16)
|
||||
}
|
||||
field(ROFF,DBF_ULONG) {
|
||||
field(ROFF,DBF_LONG) {
|
||||
prompt("Raw Offset")
|
||||
pp(TRUE)
|
||||
interest(2)
|
||||
|
||||
@@ -174,6 +174,7 @@ static long process(seqRecord *prec)
|
||||
linkDesc *plink;
|
||||
unsigned short lmask;
|
||||
int tmp;
|
||||
int index;
|
||||
|
||||
if(seqRecDebug > 10)
|
||||
printf("seqRecord: process(%s) pact = %d\n", prec->name, prec->pact);
|
||||
@@ -230,6 +231,7 @@ static long process(seqRecord *prec)
|
||||
}
|
||||
/* Figure out which links are going to be processed */
|
||||
pcb->index = 0;
|
||||
index = 0;
|
||||
plink = (linkDesc *)(&(prec->dly1));
|
||||
tmp = 1;
|
||||
while (lmask)
|
||||
@@ -241,23 +243,21 @@ static long process(seqRecord *prec)
|
||||
if ((lmask & 1) && ((plink->lnk.type != CONSTANT)||(plink->dol.type != CONSTANT)))
|
||||
{
|
||||
if (seqRecDebug > 4)
|
||||
printf(" seqRec-process Adding link %d at index %d\n", tmp, pcb->index);
|
||||
printf(" seqRec-process Adding link %d at index %d\n", tmp, index);
|
||||
|
||||
pcb->plinks[pcb->index] = plink;
|
||||
pcb->index++;
|
||||
pcb->plinks[index++] = plink;
|
||||
}
|
||||
lmask >>= 1;
|
||||
plink++;
|
||||
tmp++;
|
||||
}
|
||||
pcb->plinks[pcb->index] = NULL; /* mark the bottom of the list */
|
||||
pcb->plinks[index] = NULL; /* mark the bottom of the list */
|
||||
|
||||
if (!pcb->index)
|
||||
if (!index)
|
||||
{ /* There was nothing to do, finish record processing here */
|
||||
return(asyncFinish(prec));
|
||||
}
|
||||
|
||||
pcb->index = 0;
|
||||
/* Start doing the first forward link (We have at least one for sure) */
|
||||
processNextLink(prec);
|
||||
|
||||
@@ -367,6 +367,14 @@ static void processCallback(CALLBACK *arg)
|
||||
if (seqRecDebug > 5)
|
||||
printf("processCallback(%s) processing field index %d\n", prec->name, pcb->index+1);
|
||||
|
||||
if (pcb->plinks[pcb->index] == NULL)
|
||||
{
|
||||
static int overrun = 0;
|
||||
errlogPrintf("seq record %s: index overrun number %d in callback.\n", prec->name, ++overrun);
|
||||
dbScanUnlock((struct dbCommon *)prec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save the old value */
|
||||
myDouble = pcb->plinks[pcb->index]->dov;
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ include $(TOP)/configure/CONFIG
|
||||
PROD_IOC_DEFAULT = softIoc
|
||||
PROD_IOC_iOS = -nil-
|
||||
|
||||
PROD_LDFLAGS_vxWorks = --whole-archive
|
||||
|
||||
DBD += softIoc.dbd
|
||||
softIoc_DBD += base.dbd
|
||||
softIoc_DBD += dlload.dbd
|
||||
|
||||
27
startup/win64.bat
Normal file
27
startup/win64.bat
Normal file
@@ -0,0 +1,27 @@
|
||||
@ECHO OFF
|
||||
REM *************************************************************************
|
||||
REM Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
REM National Laboratory.
|
||||
REM Copyright (c) 2002 The Regents of the University of California, as
|
||||
REM Operator of Los Alamos National Laboratory.
|
||||
REM EPICS BASE Versions 3.13.7
|
||||
REM and higher are distributed subject to a Software License Agreement found
|
||||
REM in file LICENSE that is included with this distribution.
|
||||
|
||||
set PATH=%PATH%;C:\cygwin\bin
|
||||
REM --------------- Visual c++ ------------------------
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" amd64
|
||||
|
||||
REM --------------- CUDA -----------------------------
|
||||
|
||||
|
||||
REM --------------- EPICS -----------------------------
|
||||
REM -- R3.14 requirements
|
||||
set EPICS_HOST_ARCH=windows-x64
|
||||
set PATH=%PATH%;C:\epics\base-3.14.12.4\bin\%EPICS_HOST_ARCH%
|
||||
REM ===================================================
|
||||
REM ====== OPTIONAL ENVIRONMENT VARIABLES FOLLOW ======
|
||||
|
||||
REM ---------------- EPICS tools ----------------------
|
||||
REM -- HOST_ARCH needed for Makefile.Host builds --
|
||||
set HOST_ARCH=WIN32
|
||||
Reference in New Issue
Block a user