Compare commits

...

63 Commits

Author SHA1 Message Date
fe49fa6db3 fix for RHEL8 2023-01-27 17:21:55 +01:00
77aa003153 build host stuff only for SLx/RHELx 2023-01-27 17:10:39 +01:00
3b993e2f54 pick strange time stamps fix from 7.0 2023-01-27 10:09:23 +01:00
f9f48c5267 no license manager access with this? 2023-01-27 10:09:23 +01:00
d9105135cc add support for RHEL8 2023-01-27 10:09:23 +01:00
c7f30154f0 drop support for 32 bit SL6 2023-01-27 10:09:22 +01:00
2d6e308538 drop unused vxWorks versions 2023-01-27 10:09:14 +01:00
Straumann Till
07c5ad5d5a epicsMutexPriorityInversionTest.c: check __GLIBC_PREREQ(2,4) when compiling
(non-portable) CPU-affinity extensions only available in glibc 2.4 and
  higher.
2020-09-15 16:13:47 +02:00
Straumann Till
90f1ac3676 Changed epicsMutexPriorityInversionTest.cc -> .c (no C++ used) 2020-09-15 16:13:46 +02:00
till straumann
4b5d43b699 posix/osdMutex.c: print warning if PI envvar is set but PI not available or compiled in. 2020-09-15 16:13:46 +02:00
till straumann
043595ca0a Added test for mutex priority inheritance 2020-09-15 16:13:45 +02:00
till straumann
2c7dae92bc osdMutex.h: fixed multiple-inclusion guard 2020-09-15 16:13:45 +02:00
till straumann
76aa3aab01 Support run-time enabled priority-inheritance for epicsMutex, epicsEvent etc. 2020-09-15 16:13:44 +02:00
cc5084018b fix problem compiling for vxWorks 6.9 2020-09-15 16:11:48 +02:00
till straumann
375b74a0c0 Makefile: don't remove 'src/' if INSTALL_LOCATION is actually the TOP
Also: declare 'copysrc' and 'tar' as .PHONY: targets
2020-08-13 10:46:30 +02:00
9f97b4bce0 add vxWorks 6.9 2020-07-20 15:58:54 +02:00
a68f3d62aa add cross compilation for NI CompactRIO RT-Linux 2020-05-26 15:10:20 +02:00
a9a975b1e4 changes callbacks to use locked ring buffer 2020-05-12 12:13:06 +02:00
d94e0097a6 Got ring buffers from EPICS 7.0 for use in callbacks 2020-05-12 12:12:40 +02:00
c951229511 Got epicsSpin from EPICS 7.0 for use in in ring buffers 2020-05-12 12:11:18 +02:00
751059eea2 Merge branch 'PSI-3.14' of git.psi.ch:epics_base/base-3-14-12 into PSI-3.14 2020-05-12 11:15:29 +02:00
74bba6ec9d name tar file after full version number 2020-05-12 11:11:28 +02:00
b68e80fa15 install header needed by iocStats 2020-05-12 11:10:51 +02:00
a441443bd0 try to harden seqRecord against race condition 2020-03-04 08:43:51 +01:00
e7a300bf9e fix potential crash 2020-03-03 16:51:34 +01:00
ed1944c54b allow to add new error symbols from dynamicly loaded modules 2019-10-24 16:17:23 +02:00
b62938af2f use only 2 component VXWORKS_VERSION else VX_GNU_VERSION will not be set correctly 2019-10-23 11:30:26 +02:00
b8419ec17d don't reconnect to log server unnecessarily 2019-09-04 10:27:10 +02:00
172f170230 commit d0e831 was wrong 2019-09-03 09:33:44 +02:00
795e1a9368 don't rebuild befor making tar 2019-09-03 09:30:36 +02:00
9a3f7e3c52 : in version string gives problems with tar 2019-09-03 09:30:36 +02:00
7c5c03edb0 Use READLINE as default for all Linux targets 2019-09-03 09:30:35 +02:00
2e2b7be9bd make sure softIoc for vxWorks contains all functions 2019-09-03 09:30:35 +02:00
12af6fa231 Use perl instead of date for EPICS_SITE_VERSION because of Windows 2019-09-03 09:30:35 +02:00
d0e83116e6 merge logClient changes from 7.0.3 2019-09-03 09:30:35 +02:00
3276e22c82 Merge branch 'PSI-3.14' of git.psi.ch:epics_base/base-3-14-12 into PSI-3.14 2019-09-02 09:25:13 +02:00
8b5225c14f merged with origin/PSI-3.14 2019-05-09 16:31:51 +02:00
962bf4d2dd added newer eldk53-ppc4xxFP (DeltaTau) 2019-05-09 16:25:23 +02:00
8a53c494ff Don't build with clang for SL6 any more 2019-05-09 16:25:02 +02:00
f65c39c0d2 backport dbQuietMacroWarnings 2018-09-14 15:23:13 +02:00
26b857a8da Merge remote-tracking branch 'origin/3.14' into PSI-3.14 2018-09-14 15:17:29 +02:00
ee1b68d229 Merge remote-tracking branch 'launchpad/3.14' into PSI-3.14 2018-09-14 15:12:46 +02:00
cbd4634224 install header needed by iocStats 2018-09-14 12:00:47 +02:00
543ac1fb75 use new yocto installation for Zynq boards 2018-06-13 14:41:29 +02:00
fc3f1fab6a moved -fno-strict-aliasing to generic linux config file 2018-06-08 09:14:46 +02:00
Michael Davidsaver
4b4d302ded apply patch "db_close_events cleanup" 2018-05-28 15:51:25 +02:00
24ab504920 raspberry pi architecture added 2018-05-28 15:32:55 +02:00
2db93163c1 restore lost include line 2018-05-18 09:56:30 +02:00
2ef70f6d7c Merge branch 'PSI-3.14' of git.psi.ch:epics_base/base-3-14-12 into PSI-3.14 2018-05-04 11:20:00 +02:00
Andrew Johnson
116c90c2ea Reformatting, no code changes 2018-05-03 14:40:12 -05:00
Andrew Johnson
3f3696fb91 dbStatic: Prevent modifying a NAME field using a DB file
Fixes LP: #1597809
2018-05-03 14:28:44 -05:00
06a330ccf8 prevent time jumps in NTP client 2018-05-03 09:55:29 +02:00
ccbaf557a0 comment fixed 2018-05-03 09:54:31 +02:00
720cc3e84e Merge branch 'PSI-3.14' of git.psi.ch:epics_base/base-3-14-12 into PSI-3.14 2018-04-04 16:03:22 +02:00
6f3e74095c update osdThread.c from ../posix while keeping thread name and LWP ID 2018-04-04 11:53:45 +02:00
871e5c496e for easier debugging: overwrite destroyed event mutex 2018-04-04 10:45:40 +02:00
44d4e47ec2 add simple calculations to macros 2018-04-04 09:41:36 +02:00
394bf30dbf use dynamic vxWorks BSP function binding because we don't know which functions are implememted in any particular BSP 2018-04-04 09:40:10 +02:00
9b9daa9a7c by Helge 2018-04-04 09:37:51 +02:00
zimoch
ec3b7c364b Put thread names in ps -L output and thread ids in epicsThreadShowAll output 2018-04-04 09:31:01 +02:00
afcb81927e catch tNTP time jumps in vxWorks 2018-03-29 13:32:27 +02:00
5fe0429c48 undo change of ROFF from LONG to ULONG in commit f498b36438 2018-03-29 11:48:55 +02:00
Andrew Johnson
b9443f8813 Tell MSVC to use absolute filenames in diagnostics (-FC flag) 2018-03-23 11:39:53 -05:00
75 changed files with 2855 additions and 441 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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.

View File

@@ -1,4 +1,2 @@
# Include definitions common to linux pentium targets
include $(CONFIG)/os/CONFIG.Common.linux-x86_64
COMMANDLINE_LIBRARY = READLINE

View File

@@ -1,3 +1 @@
include $(CONFIG)/os/CONFIG.Common.linux-clang
COMMANDLINE_LIBRARY = READLINE

View File

@@ -0,0 +1 @@
include $(CONFIG)/os/CONFIG.Common.linux-x86_64

View File

@@ -0,0 +1 @@
include $(CONFIG)/os/CONFIG.Common.linux-clang

View File

@@ -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

View File

@@ -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

View File

@@ -1,3 +1 @@
include $(CONFIG)/os/CONFIG.Common.linux-clang
COMMANDLINE_LIBRARY = READLINE

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -14,4 +14,3 @@ COMMANDLINE_LIBRARY = READLINE_NCURSES
ARCH_DEP_CXXFLAGS += -Wno-psabi
ARCH_DEP_CFLAGS += -funwind-tables
ARCH_DEP_CXXFLAGS += -fno-strict-aliasing

View File

@@ -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

View 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

View 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)

View File

@@ -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

View File

@@ -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)

View 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)

View File

@@ -0,0 +1 @@
include $(CONFIG)/os/CONFIG.linux-x86_64.Common

View File

@@ -0,0 +1 @@
include $(CONFIG)/os/CONFIG.Cross_64.RHEL7-x86_64

View File

@@ -0,0 +1 @@
include $(CONFIG)/os/CONFIG.linux-x86.linux-x86

View File

@@ -0,0 +1 @@
GNU_BIN=/opt/RHEL7/bin

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,4 @@
COMMANDLINE_LIBRARY = READLINE
ifeq ($(filter SL% RHEL%,$(T_A)),)
VALID_BUILDS = Ioc
endif

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]);

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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[];

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 */

View File

@@ -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 );

View 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 */

View File

@@ -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

View 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,&param) == 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,&param);
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;
}

View 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();
}

View 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);
}

View File

@@ -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");

View File

@@ -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 */

View File

@@ -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 */

View 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;
}

View File

@@ -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");

View File

@@ -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;
}
/*

View 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();
}

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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();
}

View File

@@ -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 */

View File

@@ -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

View 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();
}

View 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";

View File

@@ -49,6 +49,7 @@ variable(CASDEBUG,int)
# dbStaticLib settings
variable(dbRecordsOnceOnly,int)
variable(dbBptNotMonotonic,int)
variable(dbQuietMacroWarnings,int)
# dbLoadTemplate settings
variable(dbTemplateMaxVars,int)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;

View File

@@ -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
View 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