changes for 3.14
This commit is contained in:
@@ -1,7 +1,77 @@
|
||||
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
include $(TOP)/config/RULES_ARCHS
|
||||
# includes to install from this sub-project
|
||||
#
|
||||
INC += drvSup.h
|
||||
INC += callback.h
|
||||
INC += dbLock.h
|
||||
INC += dbAccess.h
|
||||
INC += dbConvert.h
|
||||
INC += dbEvent.h
|
||||
INC += dbScan.h
|
||||
INC += db_access.h
|
||||
INC += dbAddr.h
|
||||
INC += db_field_log.h
|
||||
INC += initHooks.h
|
||||
INC += recSup.h
|
||||
INC += devSup.h
|
||||
INC += taskwd.h
|
||||
INC += recGbl.h
|
||||
INC += dbBkpt.h
|
||||
|
||||
MENUS += menuAlarmSevr.h
|
||||
MENUS += menuAlarmStat.h
|
||||
MENUS += menuArrType.h
|
||||
MENUS += menuCompress.h
|
||||
MENUS += menuFtype.h
|
||||
MENUS += menuIvoa.h
|
||||
MENUS += menuLinr.h
|
||||
MENUS += menuOmsl.h
|
||||
MENUS += menuPriority.h
|
||||
MENUS += menuScan.h
|
||||
MENUS += menuYesNo.h
|
||||
|
||||
RECTYPES += dbCommon.h
|
||||
USER_DBDFLAGS += -I ..
|
||||
|
||||
DBDINSTALL += dbCommonRecord.dbd
|
||||
DBDINSTALL += menuGlobal.dbd
|
||||
|
||||
#===================================================
|
||||
|
||||
USR_CFLAGS += -ansi
|
||||
|
||||
dbLib_SRCS = \
|
||||
dbLock.c\
|
||||
dbAccess.c\
|
||||
dbBkpt.c\
|
||||
dbConvert.c\
|
||||
dbFastLinkConv.c\
|
||||
dbNotify.c \
|
||||
iocInit.c\
|
||||
dbScan.c\
|
||||
dbEvent.c\
|
||||
dbTest.c\
|
||||
db_access.c\
|
||||
db_test.c\
|
||||
recGbl.c\
|
||||
callback.c\
|
||||
taskwd.c\
|
||||
dbCa.c \
|
||||
initHooks.c \
|
||||
dbcar.c
|
||||
|
||||
|
||||
IOC_LIBRARY_vxWorks = dbLib
|
||||
|
||||
#===================================================
|
||||
|
||||
include $(TOP)/configure/RULES_BUILD
|
||||
|
||||
dbCommon.h: ../dbCommonRecord.dbd ../dbCommon.dbd
|
||||
$(RM) $@
|
||||
$(EPICS_BASE)/bin/$(HOST_ARCH)/dbToRecordtypeH$(EXE) \
|
||||
$(USER_DBDFLAGS) $<
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# Makefile.Host for base/src/db
|
||||
#
|
||||
#
|
||||
|
||||
TOP = ../../..
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
# includes to install from this sub-project
|
||||
#
|
||||
INC += drvTS.h
|
||||
INC += drvSup.h
|
||||
INC += callback.h
|
||||
INC += dbLock.h
|
||||
INC += dbAccess.h
|
||||
INC += dbConvert.h
|
||||
INC += dbEvent.h
|
||||
INC += dbScan.h
|
||||
INC += db_access.h
|
||||
INC += dbAddr.h
|
||||
INC += db_field_log.h
|
||||
INC += fast_lock.h
|
||||
INC += initHooks.h
|
||||
INC += recSup.h
|
||||
INC += devSup.h
|
||||
INC += taskwd.h
|
||||
INC += recGbl.h
|
||||
INC += dbBkpt.h
|
||||
INC += devLib.h
|
||||
|
||||
MENUS += menuAlarmSevr.h
|
||||
MENUS += menuAlarmStat.h
|
||||
MENUS += menuArrType.h
|
||||
MENUS += menuCompress.h
|
||||
MENUS += menuFtype.h
|
||||
MENUS += menuIvoa.h
|
||||
MENUS += menuLinr.h
|
||||
MENUS += menuOmsl.h
|
||||
MENUS += menuPriority.h
|
||||
MENUS += menuScan.h
|
||||
MENUS += menuYesNo.h
|
||||
|
||||
RECTYPES += dbCommon.h
|
||||
USER_DBDFLAGS += -I ..
|
||||
|
||||
DBDINSTALL += dbCommonRecord.dbd
|
||||
DBDINSTALL += menuGlobal.dbd
|
||||
|
||||
include $(TOP)/config/RULES.Host
|
||||
|
||||
dbCommon.h: ../dbCommonRecord.dbd ../dbCommon.dbd
|
||||
$(RM) $@
|
||||
$(EPICS_BASE)/bin/$(HOST_ARCH)/dbToRecordtypeH$(EXE) \
|
||||
$(USER_DBDFLAGS) $<
|
||||
@@ -1,62 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
USER_DBDFLAGS += -I ..
|
||||
USR_CFLAGS += -ansi
|
||||
|
||||
SRCS.c = \
|
||||
../dbLock.c\
|
||||
../dbAccess.c\
|
||||
../dbBkpt.c\
|
||||
../dbConvert.c\
|
||||
../dbFastLinkConv.c\
|
||||
../dbNotify.c\
|
||||
../iocInit.c\
|
||||
../drvTS.c\
|
||||
../dbScan.c \
|
||||
../dbEvent.c\
|
||||
../dbTest.c\
|
||||
../db_access.c \
|
||||
../db_test.c\
|
||||
../recGbl.c\
|
||||
../callback.c\
|
||||
../taskwd.c \
|
||||
../dbCa.c\
|
||||
../dbcar.c\
|
||||
../devLib.c\
|
||||
../devLibVxWorks.c\
|
||||
../initHooks.c
|
||||
|
||||
LIBOBJS = \
|
||||
dbLock.o\
|
||||
dbAccess.o\
|
||||
dbBkpt.o\
|
||||
dbConvert.o\
|
||||
dbFastLinkConv.o\
|
||||
dbNotify.o \
|
||||
iocInit.o\
|
||||
drvTS.o\
|
||||
dbScan.o\
|
||||
dbEvent.o\
|
||||
dbTest.o\
|
||||
db_access.o\
|
||||
db_test.o\
|
||||
recGbl.o\
|
||||
callback.o\
|
||||
taskwd.o\
|
||||
dbCa.o \
|
||||
dbcar.o \
|
||||
devLib.o \
|
||||
devLibVxWorks.o
|
||||
|
||||
PROD += initHooks.o
|
||||
|
||||
LIBNAME = dbLib
|
||||
|
||||
include $(TOP)/config/RULES.Vx
|
||||
|
||||
dbCommon.h: ../dbCommonRecord.dbd ../dbCommon.dbd
|
||||
$(RM) $@
|
||||
$(EPICS_BASE)/bin/$(HOST_ARCH)/dbToRecordtypeH$(EXE) \
|
||||
$(USER_DBDFLAGS) $<
|
||||
|
||||
@@ -1,466 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.06 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]">
|
||||
<TITLE>Synchronized Time Stamp Support</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H1>
|
||||
Synchronized Time Stamp Support</H1>
|
||||
Author: Jim Kowalkowski
|
||||
<H2>
|
||||
MODIFICATION: 04AUG1998 (Marty Kraimer)</H2>
|
||||
The routine TSsetClockFromUnix was made global. Calling it forces a resynchronization
|
||||
with a host time server. This is useful to force a master timing ioc to
|
||||
resynchronize.
|
||||
<H2>
|
||||
Introduction</H2>
|
||||
|
||||
<H3>
|
||||
Purpose</H3>
|
||||
New software has been added to IOC core to maintain time stamps. The new
|
||||
software has the ability to maintain time stamps over all IOCs on a network.
|
||||
The purpose of this paper is to explain how EPICS will synchronize the
|
||||
time stamps. In addition, this paper will explain how to configure and
|
||||
use the new EPICS time stamp support software.
|
||||
<H3>
|
||||
Definitions</H3>
|
||||
Time Stamp: Two long words representing the time in seconds/nanoseconds
|
||||
past an epoch. The first long word represents the seconds past the epoch,
|
||||
the second long word represents the nanoseconds within the second. The
|
||||
EPICS epoch is currently January 1, 1990. A commonly used Unix epoch in
|
||||
January 1,1900 or in vxWorks case, January 1,1970.
|
||||
<P>Event System: A hardware based subsystem for delivering events to all
|
||||
IOCs on a network. Typical events are the "tick" event and the "reset counter"
|
||||
event.
|
||||
<P>Event System Synchronized Time: Time stamps maintained using an event
|
||||
system. The clock pulses which increment the time stamps are provided by
|
||||
a single source, all IOCs increment time stamps using the single source
|
||||
pulse.
|
||||
<P>Soft Time: Each IOC increments the time stamps using it's own internal
|
||||
clock.
|
||||
<P>Master Timing IOC: The IOC which knows the actual time and is the source
|
||||
of the actual time to all those who inquire.
|
||||
<P>Slave IOC: An IOC which relies on a master IOC to provide the actual
|
||||
time. This IOC will keep it's time stamp in sync with a master.
|
||||
<P>Soft Slave: An IOC which uses Soft Time and synchronizes it's time stamp
|
||||
with a master.
|
||||
<P>Event Slave: An IOC which uses Event System Synchronized Time to maintain
|
||||
it's time stamp. This type of IOC uses the master to verify that it's time
|
||||
stamp is correct.
|
||||
<P>Soft Master: A Master Timing IOC that maintains it's time stamp using
|
||||
a private clock.
|
||||
<P>Event Master: An IOC which uses Event System Synchronized Time and is
|
||||
a Master Timing IOC. In addition, this IOC is the source of the clock pulses.
|
||||
<H3>
|
||||
Overview</H3>
|
||||
Time stamps are maintained across IOCs using UDP with a master/slave relationship.
|
||||
A master timing IOC is responsible for knowing the actual time. A slave
|
||||
IOC uses the master to verify it's own time stamps. Time stamps are maintained
|
||||
in two fashions: using an event system or using IOC tick counters. Both
|
||||
differ radically and require some explanation.
|
||||
<H4>
|
||||
Event System Support</H4>
|
||||
The time stamp software has special requirements in order to provide event
|
||||
system synchronized time. The time stamp software assumes that hardware
|
||||
is present which has finite counters for counting pulses or ticks delivered
|
||||
to it from some master tick generator. The software further assumes that
|
||||
every so other, before the finite counters overflow, a signal or event
|
||||
will occur to reset the counters to zero. The software requires access
|
||||
to these counters at any time and notification when the "counter reset"
|
||||
arrives. The combination of hardware tick counters and reset event notification
|
||||
gives the software the ability to maintain time. If the event system supports
|
||||
other events, it is required that the software be notified of the occurrence
|
||||
of each event. The event time will be recorded in a table which holds one
|
||||
time stamp for each possible event so that a user can inquire as to when
|
||||
the event occurred.
|
||||
<H4>
|
||||
Soft Time Support</H4>
|
||||
If no event system is present, the time stamp software can operate in a
|
||||
software timing mode. In this mode, no events are available, only the current
|
||||
time can be retrieved. An IOC using soft time will increment a time stamp
|
||||
using the system clock (usually updated at 60Hz). The master/slave relationship
|
||||
allows a slave to periodically ask a master for the correct time. At this
|
||||
point the slave's time stamp can be adjusted to match the masters.
|
||||
<H4>
|
||||
Role of a Master Timing IOC</H4>
|
||||
A master timing IOC has difference responsibilities depending on if it
|
||||
is an event master or a soft master. An event master will be an event generator
|
||||
(create "tick" and "counter reset" events). When the event master detects
|
||||
a "counter reset", it broadcasts the time the event occurred to all event
|
||||
slaves on the network. The slaves can use the time stamp data to verify
|
||||
their own time. A soft timing master does not have any events, so no broadcasting
|
||||
is done. Both soft and event masters have the ability to be queried at
|
||||
any time by slaves for the current time.
|
||||
<H4>
|
||||
Role of a Slave Timing IOC</H4>
|
||||
A slave timing IOC also has difference responsibilities depending on if
|
||||
it is an event slave or a soft slave. An event slave contains hardware
|
||||
to manage "tick" and "counter reset" events. The time stamp support software
|
||||
uses this information to maintain time. An event slave will listen for
|
||||
broadcasts from the event master timing IOC and use the information to
|
||||
verify it's time. A soft slave periodically queries a master timing IOC
|
||||
to get the current time.
|
||||
<H3>
|
||||
Design Specifications Summary</H3>
|
||||
|
||||
<H4>
|
||||
Event System Synchronized Time</H4>
|
||||
All IOCs will have identical event times. In addition, all IOCs will maintain
|
||||
the same current time.
|
||||
<P>The minimum events which must be supported is two. One must be used
|
||||
as a "tick" event and one must be used as a "reset hardware tick counter"
|
||||
event. The second will be used to update the time stamp representing the
|
||||
current time.
|
||||
<P>An optional event can be used as a "heartbeat" event. This event can
|
||||
be used to signal errors.
|
||||
<H4>
|
||||
Soft Time</H4>
|
||||
All IOCs of this type will maintain time stamps which are within two clocks
|
||||
ticks or 1/30th of a second of a master. The master may be a designated
|
||||
IOC or the Unix boot server. A Unix boot server master or the server pointed
|
||||
to by the EPICS environment variable EPICS_TS_NTP_INET must have NTP available
|
||||
for polling.
|
||||
<H2>
|
||||
User Level Interface</H2>
|
||||
|
||||
<H3>
|
||||
General Use Functions</H3>
|
||||
Three functions exist in the synchronous time stamp support software for
|
||||
the user to retrieve time stamps:
|
||||
<UL>
|
||||
<LI>
|
||||
TSgetTimeStamp(event_number, struct timespec* time_stamp)</LI>
|
||||
|
||||
<LI>
|
||||
TScurrentTimeStamp(struct timespec* time_stamp)</LI>
|
||||
|
||||
<LI>
|
||||
TSgetFirstOfYearVx(struct timespec* time_stamp)</LI>
|
||||
|
||||
<LI>
|
||||
tsLocalTime(TS_STAMP*)</LI>
|
||||
</UL>
|
||||
To retrieve the time stamp which represents the time that an event occurred,
|
||||
use <B>TSgetTimeStamp()</B>. <B>TScurrentTimeStamp()</B> can be used to
|
||||
retrieve the time stamp which represents the time of day. <B>TsLocalTime()</B>
|
||||
is the function for returning the current time stamp in the old time stamp
|
||||
driver, the routine can still be used to retrieve this information. The
|
||||
function <B>TSgetFirstOfYear()</B> attempts to give the caller a time stamp
|
||||
representing January 1 of the current year relative to the vxWorks epoch
|
||||
1970.
|
||||
<P>An EPICS enironment variable named EPICS_TS_NTP_INET exists which can
|
||||
be set to point to an NTP server. The default NTP server is the IOC boot
|
||||
server.
|
||||
<H4>
|
||||
Test Functions</H4>
|
||||
The following functions can be run from the vxWorks shell to give information
|
||||
about the time stamp driver.
|
||||
<UL>
|
||||
<LI>
|
||||
<B>TSreport()</B>: Display all the information about the current configuration
|
||||
and status of this time stamp driver.</LI>
|
||||
|
||||
<LI>
|
||||
<B>TSprintRealTime()</B>: Call the ErGetTime() function described below
|
||||
(if present) and print the time stamp returned from it. Also print the
|
||||
current EPICS time stamp.</LI>
|
||||
|
||||
<LI>
|
||||
<B>TSprintTimeStamp(event_number)</B>: Print the EPICS time stamp for the
|
||||
given event_number.</LI>
|
||||
|
||||
<LI>
|
||||
<B>TSprintCurrentTime()</B>: Print the EPICS time stamp representing the
|
||||
current time.</LI>
|
||||
|
||||
<LI>
|
||||
<B>TSprintUnixTime()</B>: Send a time stamp query transaction to the boot
|
||||
server or NTP server and print the time stamp returned.</LI>
|
||||
|
||||
<LI>
|
||||
<B>TSprintMasterTime()</B>: Send a time stamp query transaction to the
|
||||
master time server and print the time stamp returned.</LI>
|
||||
</UL>
|
||||
|
||||
<H4>
|
||||
Debugging Information</H4>
|
||||
A global variable exists named <B>TSdriverDebug</B>. Setting this variable
|
||||
to a positive value in the vxWorks start up script will inform the time
|
||||
stamp driver to print information about what it is doing. The greater the
|
||||
value, the more information the driver will print. The number can be set
|
||||
and adjusted to any value any time while the IOC is running.
|
||||
<H3>
|
||||
Record Support</H3>
|
||||
Record support will have the ability to tie the record processing time
|
||||
to an event. This means that a user can specify that processing of a record
|
||||
is due to an event (from the event system). When the record gets processed,
|
||||
the time in the TIME field of the record will be the time when the event
|
||||
occurred. In order to support the event times from record support, two
|
||||
new fields will be added to dbCommon. The fields will be Time Stamp Event
|
||||
(TSE), and Time Stamp Event Link (TSEL). The TSE field will be the actual
|
||||
event time the user is interested in. The TSEL field will be a link used
|
||||
to populate the TSE.
|
||||
<P>To facilitate the use of the time stamp support software, a new record
|
||||
support function will be added:
|
||||
<UL>
|
||||
<LI>
|
||||
recGblGetTimeStamp((dbCommon*)prec).</LI>
|
||||
</UL>
|
||||
This routine uses TSgetTimeStamp(prec->tse, &prec->time) to set the
|
||||
processing time of the record. The new recGblGetTimeStamp() will replace
|
||||
the existing call to tsLocalTime(). If the TSE field is zero (the default),
|
||||
then TSgetTimeStamp() will report the current time. It is important to
|
||||
remember that if a TSE field is set, then the processing time (in field
|
||||
TIME) will always reflect the last time the event occurred.
|
||||
<H2>
|
||||
Driver Configuration</H2>
|
||||
The synchronous time stamp support software is configured by calling TSconfigure()
|
||||
from the "startup.cmd" file. The parameters to this routine are:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>master_indicator</B>: 1=master timing IOC, 0=slave timing IOC, default
|
||||
is slave.</LI>
|
||||
|
||||
<LI>
|
||||
<B>sync_rate_seconds</B>: The clock sync rate in seconds. This rate tells
|
||||
how often the synchronous time stamp support software will confirm that
|
||||
an IOC clock is synchronized. The default is 10 seconds.</LI>
|
||||
|
||||
<LI>
|
||||
<B>clock_rate_hz</B>: The frequency in hertz of the clock, the default
|
||||
is 1000Hz for the event system. The value will be set to the IOC's internal
|
||||
clock rate when soft timing is used.</LI>
|
||||
|
||||
<LI>
|
||||
<B>master_port</B>: The UDP port which a master timing IOC will use to
|
||||
receive time stamp requests. The default is 18233.</LI>
|
||||
|
||||
<LI>
|
||||
<B>slave_port</B>: The UDP port which a slave will use to receive time
|
||||
stamp information from a master.</LI>
|
||||
|
||||
<LI>
|
||||
<B>time_out</B>: UDP information request time out in milliseconds, if zero
|
||||
is entered here, the default will be used which is 250ms.</LI>
|
||||
|
||||
<LI>
|
||||
<B>type</B>: 0=normal operation, 1=force soft timing type.</LI>
|
||||
</UL>
|
||||
This routine must be run before iocInit(). The synchronous time stamp support
|
||||
software is initialized as part of iocInit. Running <B>TSreport()</B> after
|
||||
iocInit() will produce a report which shows the current state of the driver.
|
||||
<H2>
|
||||
Event System interface</H2>
|
||||
The event system interface consists of seven function which can be provided
|
||||
by an event system. The synchronous time stamp support software uses a
|
||||
card number of zero on all functions that require a card number. The functions
|
||||
are as follows:
|
||||
<UL>
|
||||
<LI>
|
||||
long ErHaveReceiver(int event_card_number)</LI>
|
||||
|
||||
<LI>
|
||||
long ErGetTicks(int event_card_number, unsigned long* ticks)</LI>
|
||||
|
||||
<LI>
|
||||
long ErRegisterEventHandler(int event_card_num,EVENT_FUNC event_func)</LI>
|
||||
|
||||
<LI>
|
||||
long ErRegisterErrorHandler(int event_card_num,ERROR_FUNC error_func)</LI>
|
||||
|
||||
<LI>
|
||||
long ErForceSync(int event_card_number)</LI>
|
||||
|
||||
<LI>
|
||||
long ErGetTime(struct timespec* time_stamp)</LI>
|
||||
|
||||
<LI>
|
||||
long ErSyncEvent()</LI>
|
||||
|
||||
<LI>
|
||||
long ErDirectTime()</LI>
|
||||
|
||||
<LI>
|
||||
long ErDriverInit()</LI>
|
||||
</UL>
|
||||
The definition are as follows:
|
||||
<UL>
|
||||
<LI>
|
||||
<B>ErHaveReceiver()</B>: Returns -1 if no event (timing) hardware present,
|
||||
else returns the number of supported events.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErGetTicks()</B>: Returns the number of ticks since the last hardware
|
||||
tick counter reset.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErRegisterEventHandler()</B>: Informs the event system of a function
|
||||
to call when an event occurs, the format of the function will be defined
|
||||
below.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErRegisterErrorHandler()</B>: Informs the event system of a function
|
||||
to call when an error occurs, the format of the function will be defined
|
||||
below.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErForceSync()</B>: This function will force an event generator to generate
|
||||
a tick reset event and send it.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErGetTime()</B>: This function returns the actual time. The intention
|
||||
here is that this function will retrieve the actual time from GPS system
|
||||
or equivalent and return is in time stamp format.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErSyncEvent()</B>: Return the event number for the tick reset event.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErDirectTime()</B>: Return 0 for normal operation, return value not
|
||||
= 0 for systems that has direct time access, such as a GPS.</LI>
|
||||
|
||||
<LI>
|
||||
<B>ErDriverInit()</B>: The time stamp driver initialization function will
|
||||
call this user supplied function before it returns and after it sets up
|
||||
the vxWorks clock and attempts to set up the TIMEZONE variable. This can
|
||||
be useful to initialize a system such as a GPS (the year can be determined
|
||||
using the vxWorks ansiTime library).</LI>
|
||||
</UL>
|
||||
All of these routines are checked to exist when the time stamp support
|
||||
code initializes. All have some kind of default routine provided if they
|
||||
are not found, most of which just return an error condition. The functions
|
||||
which the time stamp support software registers (event and error) have
|
||||
the following format:
|
||||
<UL>
|
||||
<LI>
|
||||
TSeventHandler(int Card,int EventNum,unsigned long Ticks)</LI>
|
||||
|
||||
<LI>
|
||||
TSerrorHandler(int Card, int ErrorNum)</LI>
|
||||
</UL>
|
||||
Here the Card is the event system board of interest (always zero), the
|
||||
EventNum is the event that occurred, and the Ticks is the number of ticks
|
||||
since the last board tick counter reset.
|
||||
<P>In addition to the above functions, a global variable exists on the
|
||||
IOC which can be used to indicate that direct time is available. Setting
|
||||
the variable <B>TSdirectTimeVar</B> to a nonzero value has the same effect
|
||||
as providing the ErDirectTime() function.
|
||||
<H3>
|
||||
Creating Direct Time Support</H3>
|
||||
Most of the above interface functions apply only when special event hardware
|
||||
is present. A much simpler configuration is when a GPS is present and time
|
||||
stamps are distributed using IRIG-B to all or most of the IOCs. The easiest
|
||||
way to implement this scenario is to define ErDirectTime() to return the
|
||||
value one and define ErGetTime(). The job of ErGetTime() will be to actually
|
||||
be to generate and return the time stamp representing the current time
|
||||
(from the EPICS epoch). At system initialization, the actual time is retrieved
|
||||
from a Unix server through NTP or the Unix time protocol, so that year
|
||||
will be valid in the vxWorks time clock. At the GPS driver initialization,
|
||||
the vxWorks function clock_gettime() can be used to calculate the year.
|
||||
Record support will internally eventually call ErGetTime() each time the
|
||||
record is processed. The GPS driver should be included as part of drvSup.ascii,
|
||||
so it initialized in the proper order.
|
||||
<H2>
|
||||
Operation</H2>
|
||||
An IOC can be configured to run in one of four ways: synchronous-master,
|
||||
soft-master, synchronous-slave, soft-slave. Each mode maintains time differently.
|
||||
When the time stamp support code initializes, it determines the mode which
|
||||
it will operate in based on configuration parameters and event system function
|
||||
information.
|
||||
<H3>
|
||||
Synchronous Time</H3>
|
||||
Synchronous timing is determined by the presence of event system hardware.
|
||||
The function ErHaveReceiver() gives this information. All IOCs using synchronous
|
||||
time will have the exact same time stamps. The "tick" event increments
|
||||
all IOC's event system tick counters, the "reset tick counter" resets the
|
||||
counter to zero and posts the event to the time stamp support software.
|
||||
The time stamp support software system knows the current time by looking
|
||||
at the last "tick reset event" time and querying the event system with
|
||||
ErGetTicks() for the number of ticks which have elapsed since the last
|
||||
reset. Since the event handler function gets called with the "ticks since
|
||||
last reset", an event time is the last "tick reset event" time plus the
|
||||
ticks count in the call.
|
||||
<H4>
|
||||
Master</H4>
|
||||
A synchronous master is determined by the first parameter to TSconfigure()
|
||||
and the presence of event hardware. A master must have an event generator
|
||||
and an event receiver. Since the event system is configured from EPICS
|
||||
database records, the database must have records in it to initialize the
|
||||
event system. The master is responsible for providing the "tick" event
|
||||
and the "reset tick counter" event.
|
||||
<P>When the time stamp support software's event handler function on a master
|
||||
timing IOC receives a "reset tick counter" event, a time stamp message
|
||||
is broadcast out on the slave_port (configured by TSconfigure()). The master
|
||||
timing IOC is also listening on the master_port (also configured by TSconfigure())
|
||||
for incoming requests for time stamp information.
|
||||
<P>At boot time, a master will set the vxWorks clock from the Unix boot
|
||||
server time. The time is retrieved from the boot server using NTP or the
|
||||
time protocol, or the server pointed to by the EPICS environment variable
|
||||
EPICS_TS_NTP_INET using NTP. The GPS module takes an unknown period of
|
||||
time to sync to the correct time, so it can not be used until it's time
|
||||
is valid. The event system is not up and running until record support initialization
|
||||
is complete, therefore the event system time stamps are not ticking until
|
||||
the event system initializes. At the time of the first sync, the event
|
||||
system is known to be up, and the "reset tick counter" or "sync" event
|
||||
is set to the current time (vxWorks clock).
|
||||
<H4>
|
||||
Slave</H4>
|
||||
A synchronous slave is determined by the first parameter to TSconfigure()
|
||||
and the presence of event hardware. This mode is automatically selected
|
||||
if no TSconfigure() call is used in the "startup.cmd" file. This type of
|
||||
slave must have an event receiver. The EPICS database must be configured
|
||||
to initialize the event system.
|
||||
<P>When a synchronous slave configuration is determined, the IOC broadcasts
|
||||
a request for master on the master_port port. If a master is found, then
|
||||
all current time, sync rate, and clock are extracted from the master's
|
||||
response (the sync rate and clock rate from the TSconfigure() are overwritten
|
||||
to match the master's configuration). If a master is not found, the slave
|
||||
IOC goes into a polling mode to try to find a master every two minutes.
|
||||
While a slave has no master, The IOC's clock is initialized from the Unix
|
||||
boot server and TSgetTimeStamp() returns the vxWorks time clock value.
|
||||
<P>The slave experiences the same problems as the master upon boot.
|
||||
<H3>
|
||||
Soft Time</H3>
|
||||
Soft time IOCs use the 60 hertz clock available from vxWorks to maintain
|
||||
a time stamp. The IOC will increment a time stamp at a 60 hertz rate. Soft
|
||||
time is determined by the absence of event system hardware. All soft timing
|
||||
IOC's will not have the same time stamps.
|
||||
<H4>
|
||||
Master</H4>
|
||||
A soft master is determined by the first parameter of TSconfigure() and
|
||||
the absence of event hardware. Upon boot, the master soft timing IOC retrieves
|
||||
the current time from the Unix boot server. The IOC sets up a soft time-stamp
|
||||
counter using a one tick watch dog and sets the vxWorks clock. From this
|
||||
point on, the master runs using the soft time-stamp counter. The master
|
||||
listens on the master_port port for requests for the master's current time.
|
||||
<H4>
|
||||
Slave</H4>
|
||||
A soft slave is determined by the first parameter of TSconfigure() and
|
||||
the absence of the event hardware. This mode is automatically selected
|
||||
if no TSconfigure() is present in the "startup.cmd" file. The basic operation
|
||||
of a soft slave is to synchronize the time stamp with a master when possible
|
||||
or to the Unix boot server if no master is available. Upon initialization
|
||||
the time stamp support code determines if a master is present on the network,
|
||||
and if NTP support is available from the Unix boot server or the server
|
||||
pointed to by the EPICS environment variable EPICS_TS_NTP_INET. The slave
|
||||
will request time stamps from a master or unix server at sync_rate_in_seconds
|
||||
rate from TSconfigure(). If the time stamp on the slave is found to be
|
||||
off, the clock will be incrementally adjusted so that by the next sync,
|
||||
the clock will be corrected to match the master's time stamp. A soft slave
|
||||
will automatically switch between a master and the unix boot server depending
|
||||
on if the master is available or not. In order to sync with the unix boot
|
||||
server, NTP must be available there for query only.
|
||||
<HR>
|
||||
<P>Home page for <A HREF="http://www.aps.anl.gov/asd/controls/hideos/jimk.html">Jim
|
||||
Kowalkowski</A> .
|
||||
<BR>Argonne National Laboratory <A HREF="http://www.aps.anl.gov/asd/controls/epics_copyright.html">Copyright</A>
|
||||
Information
|
||||
<ADDRESS>
|
||||
jbk@aps.anl.gov (Jim Kowalkowski)</ADDRESS>
|
||||
|
||||
<BR>updated 8/10/95
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -5,63 +5,43 @@
|
||||
/*
|
||||
* Original Author: Marty Kraimer
|
||||
* Date: 07-18-91
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 12-12-91 mrk moved from dbScan.c to callback.c
|
||||
* .02 04-23-92 jba Fixed test on priority
|
||||
* .03 06-28-93 mrk In callbackRequest replaced errMessage by logMsg
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <semLib.h>
|
||||
#include <rngLib.h>
|
||||
#include <logLib.h>
|
||||
#include <intLib.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "callback.h"
|
||||
#include "dbAccess.h"
|
||||
#include "recSup.h"
|
||||
#include "taskwd.h"
|
||||
#include "errMdef.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "task_params.h"
|
||||
/********************COPYRIGHT NOTIFICATION**********************************
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
****************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "osiSem.h"
|
||||
#include "osiThread.h"
|
||||
#include "osiInterrupt.h"
|
||||
#include "osiRing.h"
|
||||
#include "errlog.h"
|
||||
#include "callback.h"
|
||||
#include "dbAccess.h"
|
||||
#include "recSup.h"
|
||||
#include "taskwd.h"
|
||||
#include "errMdef.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
|
||||
int callbackQueueSize = 2000;
|
||||
static SEM_ID callbackSem[NUM_CALLBACK_PRIORITIES];
|
||||
static RING_ID callbackQ[NUM_CALLBACK_PRIORITIES];
|
||||
static int callbackTaskId[NUM_CALLBACK_PRIORITIES];
|
||||
static semId callbackSem[NUM_CALLBACK_PRIORITIES];
|
||||
static ringId callbackQ[NUM_CALLBACK_PRIORITIES];
|
||||
static threadId callbackTaskId[NUM_CALLBACK_PRIORITIES];
|
||||
static int ringOverflow[NUM_CALLBACK_PRIORITIES];
|
||||
volatile int callbackRestart=FALSE;
|
||||
|
||||
static int priorityValue[NUM_CALLBACK_PRIORITIES] = {0,1,2};
|
||||
|
||||
/* forward references */
|
||||
static void wdCallback(long ind); /*callback from taskwd*/
|
||||
static void wdCallback(int *ind); /*callback from taskwd*/
|
||||
static void start(int ind); /*start or restart a callbackTask*/
|
||||
|
||||
/*public routines */
|
||||
@@ -86,51 +66,43 @@ long callbackInit()
|
||||
void callbackRequest(CALLBACK *pcallback)
|
||||
{
|
||||
int priority = pcallback->priority;
|
||||
int lockKey;
|
||||
int nput;
|
||||
static int status;
|
||||
int lockKey;
|
||||
|
||||
if(priority<0 || priority>=(NUM_CALLBACK_PRIORITIES)) {
|
||||
|
||||
logMsg("callbackRequest called with invalid priority\n",0,0,0,0,0,0);
|
||||
epicsPrintf("callbackRequest called with invalid priority\n");
|
||||
return;
|
||||
}
|
||||
if(ringOverflow[priority]) return;
|
||||
lockKey = intLock();
|
||||
nput = rngBufPut(callbackQ[priority],(void *)&pcallback,sizeof(pcallback));
|
||||
intUnlock(lockKey);
|
||||
lockKey = interruptLock();
|
||||
nput = ringPut(callbackQ[priority],(void *)&pcallback,sizeof(pcallback));
|
||||
interruptUnlock(lockKey);
|
||||
if(nput!=sizeof(pcallback)){
|
||||
logMsg("callbackRequest ring buffer full\n",0,0,0,0,0,0);
|
||||
epicsPrintf("callbackRequest ring buffer full\n");
|
||||
ringOverflow[priority] = TRUE;
|
||||
}
|
||||
if((status=semGive(callbackSem[priority]))!=OK) {
|
||||
/*semGive randomly returns garbage value*/
|
||||
/*
|
||||
logMsg("semGive returned error in callbackRequest\n",0,0,0,0,0,0);
|
||||
*/
|
||||
}
|
||||
semBinaryGive(callbackSem[priority]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* General purpose callback task */
|
||||
/*static*/
|
||||
void callbackTask(int priority)
|
||||
static void callbackTask(int *ppriority)
|
||||
{
|
||||
int priority = *ppriority;
|
||||
CALLBACK *pcallback;
|
||||
int nget;
|
||||
|
||||
ringOverflow[priority] = FALSE;
|
||||
while(TRUE) {
|
||||
/* wait for somebody to wake us up */
|
||||
if(semTake(callbackSem[priority],WAIT_FOREVER)!=OK ){
|
||||
errMessage(0,"semTake returned error in callbackTask\n");
|
||||
taskSuspend(0);
|
||||
}
|
||||
while(rngNBytes(callbackQ[priority])>=sizeof(pcallback)) {
|
||||
nget = rngBufGet(callbackQ[priority],(void *)&pcallback,sizeof(pcallback));
|
||||
semBinaryTakeAssert(callbackSem[priority]);
|
||||
while(TRUE) {
|
||||
nget = ringGet(callbackQ[priority],
|
||||
(void *)&pcallback,sizeof(pcallback));
|
||||
if(nget==0) break;
|
||||
if(nget!=sizeof(pcallback)) {
|
||||
errMessage(0,"rngBufGet failed in callbackTask");
|
||||
taskSuspend(0);
|
||||
errMessage(0,"ringGet failed in callbackTask");
|
||||
threadSuspend(threadGetIdSelf());
|
||||
}
|
||||
ringOverflow[priority] = FALSE;
|
||||
(*pcallback->callback)(pcallback);
|
||||
@@ -141,42 +113,40 @@ void callbackRequest(CALLBACK *pcallback)
|
||||
static char *priorityName[3] = {"Low","Medium","High"};
|
||||
static void start(int ind)
|
||||
{
|
||||
int priority;
|
||||
char taskName[20];
|
||||
unsigned int priority;
|
||||
char taskName[20];
|
||||
|
||||
if((callbackSem[ind] = semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL)
|
||||
errMessage(0,"semBcreate failed while starting a callback task\n");
|
||||
if(ind==0) priority = CALLBACK_PRI_LOW;
|
||||
else if(ind==1) priority = CALLBACK_PRI_MEDIUM;
|
||||
else if(ind==2) priority = CALLBACK_PRI_HIGH;
|
||||
if((callbackSem[ind] = semBinaryCreate(semEmpty))==0)
|
||||
errMessage(0,"semBinaryCreate failed while starting a callback task\n");
|
||||
if(ind==0) priority = threadPriorityScanLow - 1;
|
||||
else if(ind==1) priority = threadPriorityScanLow +4;
|
||||
else if(ind==2) priority = threadPriorityScanHigh + 1;
|
||||
else {
|
||||
errMessage(0,"semBcreate failed while starting a callback task\n");
|
||||
errMessage(0,"callback start called with illegal priority\n");
|
||||
return;
|
||||
}
|
||||
if((callbackQ[ind]=rngCreate(sizeof(CALLBACK *)*callbackQueueSize)) == NULL)
|
||||
errMessage(0,"rngCreate failed while starting a callback task");
|
||||
if((callbackQ[ind]=ringCreate(sizeof(CALLBACK *)*callbackQueueSize)) == 0)
|
||||
errMessage(0,"ringCreate failed while starting a callback task");
|
||||
sprintf(taskName,"cb%s",priorityName[ind]);
|
||||
callbackTaskId[ind] = taskSpawn(taskName,priority,
|
||||
CALLBACK_OPT,CALLBACK_STACK,
|
||||
(FUNCPTR)callbackTask,ind,
|
||||
0,0,0,0,0,0,0,0,0);
|
||||
if(callbackTaskId[ind]==ERROR) {
|
||||
callbackTaskId[ind] = threadCreate(taskName,priority,
|
||||
threadGetStackSize(threadStackBig),(THREADFUNC)callbackTask,
|
||||
&priorityValue[ind]);
|
||||
if(callbackTaskId[ind]==0) {
|
||||
errMessage(0,"Failed to spawn a callback task");
|
||||
return;
|
||||
}
|
||||
taskwdInsert(callbackTaskId[ind],wdCallback,(void *)(long)ind);
|
||||
taskwdInsert(callbackTaskId[ind],wdCallback,&priorityValue[ind]);
|
||||
}
|
||||
|
||||
|
||||
static void wdCallback(long ind)
|
||||
static void wdCallback(int *pind)
|
||||
{
|
||||
int ind = *pind;
|
||||
taskwdRemove(callbackTaskId[ind]);
|
||||
if(!callbackRestart)return;
|
||||
if(taskDelete(callbackTaskId[ind])!=OK)
|
||||
errMessage(0,"taskDelete failed while restarting a callback task\n");
|
||||
if(semDelete(callbackSem[ind])!=OK)
|
||||
errMessage(0,"semDelete failed while restarting a callback task\n");
|
||||
rngDelete(callbackQ[ind]);
|
||||
threadDestroy(callbackTaskId[ind]);
|
||||
semBinaryDestroy(callbackSem[ind]);
|
||||
ringDelete(callbackQ[ind]);
|
||||
start(ind);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,29 +4,15 @@
|
||||
/*
|
||||
* Original Author: Marty Kraimer
|
||||
* Date: 07-18-91
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
*/
|
||||
|
||||
/********************COPYRIGHT NOTIFICATION**********************************
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
****************************************************************************/
|
||||
|
||||
/* Modification Log:
|
||||
* -----------------
|
||||
* .01 12-12-91 mrk Initial version
|
||||
* .02 04-05-94 mrk Remove casts on Lvalues (ANSI forbids)
|
||||
@@ -34,10 +20,10 @@
|
||||
* windows
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef INCcallbackh
|
||||
#define INCcallbackh 1
|
||||
|
||||
|
||||
/*
|
||||
* WINDOWS also has a "CALLBACK" type def
|
||||
*/
|
||||
@@ -90,5 +76,4 @@ void callbackRequestProcessCallback();
|
||||
int callbackSetQueueSize();
|
||||
#endif /*__STDC__*/
|
||||
|
||||
|
||||
#endif /*INCcallbackh*/
|
||||
|
||||
@@ -4,28 +4,14 @@
|
||||
* Original Author: Bob Dalesio
|
||||
* Current Author: Marty Kraimer
|
||||
* Date: 11-7-90
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*/
|
||||
|
||||
/********************COPYRIGHT NOTIFICATION**********************************
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
****************************************************************************/
|
||||
/*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 07-26-91 mrk Allow choices to be retrieved as numeric
|
||||
@@ -53,36 +39,33 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <taskLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "fast_lock.h"
|
||||
#include "cvtFast.h"
|
||||
#include "alarm.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbEvent.h"
|
||||
#include "db_field_log.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
#include "asLib.h"
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "cantProceed.h"
|
||||
#include "cvtFast.h"
|
||||
#include "alarm.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbEvent.h"
|
||||
#include "db_field_log.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
#include "asLib.h"
|
||||
|
||||
extern struct dbBase *pdbbase;
|
||||
extern long lset_stack_not_empty;
|
||||
@@ -565,7 +548,8 @@ long dbProcess(dbCommon *precord)
|
||||
|
||||
/* check for trace processing*/
|
||||
if (tpro) {
|
||||
if (vxTas(&trace)) {
|
||||
if(trace==0) {
|
||||
trace = 1;
|
||||
trace_lset = lset;
|
||||
set_trace = TRUE;
|
||||
}
|
||||
@@ -804,9 +788,7 @@ long dbGetLinkValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
}
|
||||
if(poptions) *poptions = 0;
|
||||
} else {
|
||||
status = -1;
|
||||
errMessage(-1,"dbGetLinkValue: Illegal link type");
|
||||
taskSuspend(0);
|
||||
cantProceed("dbGetLinkValue: Illegal link type");
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
@@ -843,9 +825,7 @@ long dbPutLinkValue(struct link *plink,short dbrType,
|
||||
if(status < 0)
|
||||
recGblSetSevr(psource,LINK_ALARM,INVALID_ALARM);
|
||||
} else {
|
||||
status=-1;
|
||||
errMessage(-1,"dbPutLinkValue: Illegal link type");
|
||||
taskSuspend(0);
|
||||
cantProceed("dbPutLinkValue: Illegal link type");
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -33,9 +33,7 @@ of this distribution.
|
||||
#include <dbBase.h>
|
||||
#include <dbFldTypes.h>
|
||||
#include <link.h>
|
||||
#ifdef vxWorks
|
||||
#include <dbCommon.h>
|
||||
#endif
|
||||
#include <dbLock.h>
|
||||
#include <tsDefs.h>
|
||||
#include <callback.h>
|
||||
|
||||
272
src/db/dbBkpt.c
272
src/db/dbBkpt.c
@@ -3,31 +3,20 @@
|
||||
/*
|
||||
* Author: Matthew Needes
|
||||
* Date: 8-30-93
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
*/
|
||||
|
||||
/********************COPYRIGHT NOTIFICATION**********************************
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
****************************************************************************/
|
||||
|
||||
/* Modification Log:
|
||||
* -----------------
|
||||
* $Log$
|
||||
* Revision 1.9 1998/01/20 16:19:48 mrk
|
||||
* Fix include statements
|
||||
*
|
||||
* Revision 1.8 1996/08/05 19:33:40 jhill
|
||||
* removed ; from if
|
||||
*
|
||||
@@ -66,35 +55,31 @@
|
||||
|
||||
/* #define BKPT_DIAG */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <lstLib.h>
|
||||
#include <types.h>
|
||||
#include <memLib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdioLib.h>
|
||||
#include <string.h>
|
||||
#include <taskLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "fast_lock.h"
|
||||
#include "alarm.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "db_field_log.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
#include "task_params.h"
|
||||
#include "dbDefs.h"
|
||||
#include "osiClock.h"
|
||||
#include "osiThread.h"
|
||||
#include "osiSem.h"
|
||||
#include "ellLib.h"
|
||||
#include "errlog.h"
|
||||
#include "alarm.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "dbBkpt.h"
|
||||
#include "db_field_log.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
|
||||
/* private routines */
|
||||
static void dbBkptCont();
|
||||
@@ -176,8 +161,8 @@ long lset_stack_not_empty = 0;
|
||||
* The semaphore is used to prevent conflicts while
|
||||
* operating with this stack.
|
||||
*/
|
||||
static LIST lset_stack;
|
||||
static SEM_ID bkpt_stack_sem;
|
||||
static ELLLIST lset_stack;
|
||||
static semId bkpt_stack_sem;
|
||||
|
||||
/*
|
||||
* Stores the last lockset continued or stepped from.
|
||||
@@ -194,10 +179,10 @@ static unsigned long last_lset = 0;
|
||||
* is returned in "pnode."
|
||||
*/
|
||||
#define FIND_LOCKSET(precord, pnode) \
|
||||
pnode = (struct LS_LIST *) lstFirst(&lset_stack); \
|
||||
pnode = (struct LS_LIST *) ellFirst(&lset_stack); \
|
||||
while ((pnode) != NULL) { \
|
||||
if (pnode->l_num == dbLockGetLockId(precord)) break; \
|
||||
pnode = (struct LS_LIST *) lstNext((NODE *)pnode); \
|
||||
pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode); \
|
||||
} \
|
||||
|
||||
/*
|
||||
@@ -208,10 +193,10 @@ static unsigned long last_lset = 0;
|
||||
* being searched for in *pep_queue.
|
||||
*/
|
||||
#define FIND_QUEUE_ENTRY(pep_queue, pqe, precord) \
|
||||
pqe = (struct EP_LIST *) lstFirst(pep_queue); \
|
||||
pqe = (struct EP_LIST *) ellFirst(pep_queue); \
|
||||
while ((pqe) != NULL) { \
|
||||
if ((pqe)->entrypoint == (precord)) break; \
|
||||
pqe = (struct EP_LIST *) lstNext((NODE *)pqe); \
|
||||
pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe); \
|
||||
} \
|
||||
|
||||
/*
|
||||
@@ -233,13 +218,13 @@ static long FIND_CONT_NODE(
|
||||
* Search through stack, taking the first entry that
|
||||
* is currently stopped at a breakpoint.
|
||||
*/
|
||||
pnode = (struct LS_LIST *) lstFirst(&lset_stack);
|
||||
pnode = (struct LS_LIST *) ellFirst(&lset_stack);
|
||||
while (pnode != NULL) {
|
||||
if (pnode->precord != NULL) {
|
||||
precord = pnode->precord;
|
||||
break;
|
||||
}
|
||||
pnode = (struct LS_LIST *) lstNext((NODE *)pnode);
|
||||
pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode);
|
||||
}
|
||||
|
||||
if (pnode == NULL) {
|
||||
@@ -315,17 +300,17 @@ long dbb(char *record_name)
|
||||
*/
|
||||
if (! lset_stack_not_empty) {
|
||||
/* initialize list and semaphore */
|
||||
bkpt_stack_sem = semBCreate(SEM_Q_FIFO, SEM_FULL);
|
||||
if (bkpt_stack_sem == NULL) {
|
||||
bkpt_stack_sem = semMutexCreate();
|
||||
if (bkpt_stack_sem == 0) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
return(1);
|
||||
}
|
||||
lstInit(&lset_stack);
|
||||
ellInit(&lset_stack);
|
||||
lset_stack_not_empty = 1;
|
||||
}
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
@@ -335,30 +320,30 @@ long dbb(char *record_name)
|
||||
if (pnode == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
pnode->precord = NULL;
|
||||
|
||||
/* initialize breakpoint list */
|
||||
lstInit(&pnode->bp_list);
|
||||
ellInit(&pnode->bp_list);
|
||||
|
||||
/* initialize entry point queue */
|
||||
lstInit(&pnode->ep_queue);
|
||||
ellInit(&pnode->ep_queue);
|
||||
|
||||
/* create execution semaphore */
|
||||
pnode->ex_sem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
|
||||
pnode->ex_sem = semBinaryCreate(semEmpty);
|
||||
if (pnode->ex_sem == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
|
||||
pnode->taskid = 0;
|
||||
pnode->step = 0;
|
||||
pnode->l_num = dbLockGetLockId(precord);
|
||||
lstAdd(&lset_stack, (NODE *)pnode);
|
||||
ellAdd(&lset_stack, (ELLNODE *)pnode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -368,11 +353,11 @@ long dbb(char *record_name)
|
||||
if (pbl == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
pbl->precord = precord;
|
||||
lstAdd(&pnode->bp_list, (NODE *)pbl);
|
||||
ellAdd(&pnode->bp_list, (ELLNODE *)pbl);
|
||||
|
||||
/*
|
||||
* Turn on breakpoint field in record
|
||||
@@ -387,20 +372,19 @@ long dbb(char *record_name)
|
||||
/*
|
||||
* Spawn continuation task
|
||||
*/
|
||||
pnode->taskid = taskSpawn(BKPT_CONT_NAME, PERIODSCAN_PRI, BKPT_CONT_OPT,
|
||||
BKPT_CONT_STACK, (FUNCPTR) dbBkptCont,(int) precord,
|
||||
0,0,0,0,0,0,0,0,0);
|
||||
|
||||
if (pnode->taskid == ERROR) {
|
||||
pnode->taskid = threadCreate("bkptCont",threadPriorityScanLow-1,
|
||||
threadGetStackSize(threadStackBig),
|
||||
(THREADFUNC)dbBkptCont,precord);
|
||||
if (pnode->taskid == 0) {
|
||||
printf(" BKPT> Cannot spawn task to process record\n");
|
||||
pnode->taskid = 0;
|
||||
dbScanUnlock(precord);
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
return(0);
|
||||
}
|
||||
@@ -439,7 +423,7 @@ long dbd(char *record_name)
|
||||
|
||||
dbScanLock(precord);
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
@@ -448,7 +432,7 @@ long dbd(char *record_name)
|
||||
printf(" BKPT> Logic Error in dbd()\n");
|
||||
precord->bkpt &= BKPT_OFF_MASK;
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
return(S_db_bkptLogic);
|
||||
}
|
||||
@@ -458,20 +442,20 @@ long dbd(char *record_name)
|
||||
*/
|
||||
|
||||
/* find record in list */
|
||||
pbl = (struct BP_LIST *) lstFirst(&pnode->bp_list);
|
||||
pbl = (struct BP_LIST *) ellFirst(&pnode->bp_list);
|
||||
while (pbl != NULL) {
|
||||
if (pbl->precord == precord) {
|
||||
lstDelete(&pnode->bp_list, (NODE *)pbl);
|
||||
ellDelete(&pnode->bp_list, (ELLNODE *)pbl);
|
||||
free(pbl);
|
||||
break;
|
||||
}
|
||||
pbl = (struct BP_LIST *) lstNext((NODE *)pbl);
|
||||
pbl = (struct BP_LIST *) ellNext((ELLNODE *)pbl);
|
||||
}
|
||||
|
||||
if (pbl == NULL) {
|
||||
printf(" BKPT> Logic Error in dbd()\n");
|
||||
precord->bkpt &= BKPT_OFF_MASK;
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
return(S_db_bkptLogic);
|
||||
}
|
||||
@@ -485,10 +469,10 @@ long dbd(char *record_name)
|
||||
* If there are no more breakpoints, give up semaphore
|
||||
* to cause the bkptCont task to quit.
|
||||
*/
|
||||
if (lstCount(&pnode->bp_list) == 0)
|
||||
semGive(pnode->ex_sem);
|
||||
if (ellCount(&pnode->bp_list) == 0)
|
||||
semBinaryGive(pnode->ex_sem);
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
|
||||
dbScanUnlock(precord);
|
||||
return(0);
|
||||
@@ -506,11 +490,11 @@ long dbc(char *record_name)
|
||||
struct dbCommon *precord = NULL;
|
||||
long status = 0;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
status = FIND_CONT_NODE(record_name, &pnode, &precord);
|
||||
if (status) {
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -529,13 +513,8 @@ long dbc(char *record_name)
|
||||
* for a record with a breakpoint. This occurs
|
||||
* because stepping mode has been switched off.
|
||||
*/
|
||||
if (taskResume(pnode->taskid) == ERROR) {
|
||||
printf(" BKPT> Cannot continue\n");
|
||||
semGive(bkpt_stack_sem);
|
||||
return(S_db_cntCont);
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
threadResume(pnode->taskid);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -550,11 +529,11 @@ long dbs(char *record_name)
|
||||
struct dbCommon *precord = NULL;
|
||||
long status = 0;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
status = FIND_CONT_NODE(record_name, &pnode, &precord);
|
||||
if (status) {
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -563,13 +542,8 @@ long dbs(char *record_name)
|
||||
|
||||
last_lset = pnode->l_num;
|
||||
|
||||
if (taskResume(pnode->taskid) == ERROR) {
|
||||
printf(" BKPT> Cannot step\n");
|
||||
semGive(bkpt_stack_sem);
|
||||
return(S_db_cntCont);
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
threadResume(pnode->taskid);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -591,7 +565,7 @@ static void dbBkptCont(struct dbCommon *precord)
|
||||
* Reset breakpoint, process record, and
|
||||
* reset bkpt field in record
|
||||
*/
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
|
||||
@@ -607,15 +581,15 @@ static void dbBkptCont(struct dbCommon *precord)
|
||||
*/
|
||||
do {
|
||||
/* Give up semaphore before waiting to run ... */
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
|
||||
/* Wait to run */
|
||||
semTake(pnode->ex_sem, WAIT_FOREVER);
|
||||
semBinaryTakeAssert(pnode->ex_sem);
|
||||
|
||||
/* Bkpt stack must still be stable ! */
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
pqe = (struct EP_LIST *) lstFirst(&pnode->ep_queue);
|
||||
pqe = (struct EP_LIST *) ellFirst(&pnode->ep_queue);
|
||||
|
||||
/* Run through entrypoint queue */
|
||||
while (pqe != NULL) {
|
||||
@@ -633,22 +607,22 @@ static void dbBkptCont(struct dbCommon *precord)
|
||||
pqe->sched = 0;
|
||||
pnode->step = 0;
|
||||
}
|
||||
pqe = (struct EP_LIST *) lstNext((NODE *)pqe);
|
||||
pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe);
|
||||
}
|
||||
|
||||
/* Reset precord. (Since no records are at a breakpoint) */
|
||||
pnode->precord = NULL;
|
||||
}
|
||||
while (lstCount(&pnode->bp_list) != 0);
|
||||
while (ellCount(&pnode->bp_list) != 0);
|
||||
|
||||
/* remove node from lockset stack */
|
||||
lstDelete(&lset_stack, (NODE *)pnode);
|
||||
ellDelete(&lset_stack, (ELLNODE *)pnode);
|
||||
|
||||
/* free entrypoint queue */
|
||||
lstFree(&pnode->ep_queue);
|
||||
ellFree(&pnode->ep_queue);
|
||||
|
||||
/* remove execution semaphore */
|
||||
semDelete(pnode->ex_sem);
|
||||
semBinaryDestroy(pnode->ex_sem);
|
||||
|
||||
printf("\n BKPT> End debug of lockset %lu\n-> ", pnode->l_num);
|
||||
|
||||
@@ -656,14 +630,14 @@ static void dbBkptCont(struct dbCommon *precord)
|
||||
free(pnode);
|
||||
|
||||
/* if last node on stack ... */
|
||||
if (lstCount(&lset_stack) == 0) {
|
||||
if (ellCount(&lset_stack) == 0) {
|
||||
/* Unset flag, delete stack semaphore */
|
||||
lset_stack_not_empty = 0;
|
||||
semDelete(bkpt_stack_sem);
|
||||
semMutexDestroy(bkpt_stack_sem);
|
||||
}
|
||||
|
||||
if (lset_stack_not_empty)
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -699,9 +673,9 @@ int dbBkpt(struct dbCommon *precord)
|
||||
* goodness breakpoint checking is turned off during
|
||||
* normal operation.
|
||||
*/
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
FIND_LOCKSET(precord, pnode);
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
|
||||
if (pnode == NULL) {
|
||||
/* no breakpoints in precord's lockset */
|
||||
@@ -730,7 +704,7 @@ int dbBkpt(struct dbCommon *precord)
|
||||
* source, queue its execution, but dump out of dbProcess without
|
||||
* calling record support.
|
||||
*/
|
||||
if (pnode->taskid && (taskIdSelf() != pnode->taskid)) {
|
||||
if (pnode->taskid && (threadGetIdSelf() != pnode->taskid)) {
|
||||
/* CONTINUE TASK CANNOT ENTER HERE */
|
||||
|
||||
/*
|
||||
@@ -748,7 +722,7 @@ int dbBkpt(struct dbCommon *precord)
|
||||
|
||||
pqe->entrypoint = precord;
|
||||
pqe->count = 1;
|
||||
pqe->time = tickGet();
|
||||
pqe->time = clockGetCurrentTick();
|
||||
pqe->sched = 0;
|
||||
|
||||
#ifdef BKPT_DIAG
|
||||
@@ -758,12 +732,12 @@ int dbBkpt(struct dbCommon *precord)
|
||||
/*
|
||||
* Take semaphore, wait on continuation task
|
||||
*/
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
/* Add entry to queue */
|
||||
lstAdd(&pnode->ep_queue, (NODE *)pqe);
|
||||
ellAdd(&pnode->ep_queue, (ELLNODE *)pqe);
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
}
|
||||
else {
|
||||
if (pqe->count < MAX_EP_COUNT)
|
||||
@@ -779,7 +753,7 @@ int dbBkpt(struct dbCommon *precord)
|
||||
* Release the semaphore, letting the continuation
|
||||
* task begin execution of the new entrypoint.
|
||||
*/
|
||||
semGive(pnode->ex_sem);
|
||||
semBinaryGive(pnode->ex_sem);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
@@ -814,8 +788,8 @@ int dbBkpt(struct dbCommon *precord)
|
||||
pnode->precord = precord;
|
||||
|
||||
/* Move current lockset to top of stack */
|
||||
lstDelete(&lset_stack, (NODE *)pnode);
|
||||
lstInsert(&lset_stack, NULL, (NODE *)pnode);
|
||||
ellDelete(&lset_stack, (ELLNODE *)pnode);
|
||||
ellInsert(&lset_stack, NULL, (ELLNODE *)pnode);
|
||||
/*
|
||||
* Unlock database while the task suspends itself. This
|
||||
* is done so that dbb() dbd() dbc() dbs() may be used
|
||||
@@ -825,11 +799,11 @@ int dbBkpt(struct dbCommon *precord)
|
||||
* continue to be processed. Cross your fingers, this
|
||||
* might actually work !
|
||||
*/
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
dbScanUnlock(precord);
|
||||
taskSuspend(pnode->taskid);
|
||||
threadSuspend(pnode->taskid);
|
||||
dbScanLock(precord);
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
@@ -860,19 +834,19 @@ long dbp(char *record_name, int interest_level)
|
||||
struct dbCommon *precord;
|
||||
int status;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
/* find pnode and precord pointers */
|
||||
status = FIND_CONT_NODE(record_name, &pnode, &precord);
|
||||
if (status) {
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/* print out record's fields */
|
||||
dbpr(precord->name, (interest_level == 0) ? 2 : interest_level);
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -916,40 +890,40 @@ long dbstat()
|
||||
struct EP_LIST *pqe;
|
||||
unsigned long time;
|
||||
|
||||
semTake(bkpt_stack_sem, WAIT_FOREVER);
|
||||
semMutexTakeAssert(bkpt_stack_sem);
|
||||
|
||||
time = tickGet();
|
||||
time = clockGetCurrentTick();
|
||||
|
||||
/*
|
||||
* Traverse list, reporting stopped records
|
||||
*/
|
||||
pnode = (struct LS_LIST *) lstFirst(&lset_stack);
|
||||
pnode = (struct LS_LIST *) ellFirst(&lset_stack);
|
||||
while (pnode != NULL) {
|
||||
if (pnode->precord != NULL) {
|
||||
|
||||
printf("LSet: %lu Stopped at: %-28.28s #B: %5.5d T: 0x%7.7x\n",
|
||||
pnode->l_num, pnode->precord->name, lstCount(&pnode->bp_list), pnode->taskid);
|
||||
printf("LSet: %lu Stopped at: %-28.28s #B: %5.5d T: %p\n",
|
||||
pnode->l_num, pnode->precord->name, ellCount(&pnode->bp_list), pnode->taskid);
|
||||
|
||||
/* for each entrypoint detected, print out entrypoint statistics */
|
||||
pqe = (struct EP_LIST *) lstFirst(&pnode->ep_queue);
|
||||
pqe = (struct EP_LIST *) ellFirst(&pnode->ep_queue);
|
||||
while (pqe != NULL) {
|
||||
if (time - pqe->time) {
|
||||
printf(" Entrypoint: %-28.28s #C: %5.5lu C/S: %7.1f\n",
|
||||
pqe->entrypoint->name, pqe->count,
|
||||
vxTicksPerSecond * pqe->count/((double)(time-pqe->time)));
|
||||
clockGetRate() * pqe->count/((double)(time-pqe->time)));
|
||||
}
|
||||
pqe = (struct EP_LIST *) lstNext((NODE *)pqe);
|
||||
pqe = (struct EP_LIST *) ellNext((ELLNODE *)pqe);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("LSet: %lu #B: %5.5d T: 0x%7.7x\n",
|
||||
pnode->l_num, lstCount(&pnode->bp_list), pnode->taskid);
|
||||
printf("LSet: %lu #B: %5.5d T: %p\n",
|
||||
pnode->l_num, ellCount(&pnode->bp_list), pnode->taskid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out breakpoints set in the lock set
|
||||
*/
|
||||
pbl = (struct BP_LIST *) lstFirst(&pnode->bp_list);
|
||||
pbl = (struct BP_LIST *) ellFirst(&pnode->bp_list);
|
||||
while (pbl != NULL) {
|
||||
printf(" Breakpoint: %-28.28s", pbl->precord->name);
|
||||
|
||||
@@ -959,13 +933,13 @@ long dbstat()
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
pbl = (struct BP_LIST *) lstNext((NODE *)pbl);
|
||||
pbl = (struct BP_LIST *) ellNext((ELLNODE *)pbl);
|
||||
}
|
||||
|
||||
pnode = (struct LS_LIST *) lstNext((NODE *)pnode);
|
||||
pnode = (struct LS_LIST *) ellNext((ELLNODE *)pnode);
|
||||
}
|
||||
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1001,7 +975,7 @@ long dbprc(char *record_name)
|
||||
/* Reset breakpoints */
|
||||
int dbreset()
|
||||
{
|
||||
semGive(bkpt_stack_sem);
|
||||
semMutexGive(bkpt_stack_sem);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
#ifndef INCdbBkptsh
|
||||
#define INCdbBkptsh 1
|
||||
|
||||
#include <lstLib.h>
|
||||
#include <ellLib.h>
|
||||
#include <osiSem.h>
|
||||
#include <osiThread.h>
|
||||
/* Needs to be put into dbTest.h ! */
|
||||
long dbpr(char *name, int level);
|
||||
|
||||
@@ -42,8 +44,8 @@ long dbpr(char *name, int level);
|
||||
*/
|
||||
|
||||
struct BP_LIST {
|
||||
NODE *next_list;
|
||||
NODE *prev_list;
|
||||
ELLNODE *next_list;
|
||||
ELLNODE *prev_list;
|
||||
struct dbCommon *precord;
|
||||
};
|
||||
|
||||
@@ -52,8 +54,8 @@ struct BP_LIST {
|
||||
* detected for a lockset.
|
||||
*/
|
||||
struct EP_LIST {
|
||||
NODE *next_list;
|
||||
NODE *prev_list;
|
||||
ELLNODE *next_list;
|
||||
ELLNODE *prev_list;
|
||||
struct dbCommon *entrypoint; /* pointer to entry point in lockset */
|
||||
unsigned long count; /* number of times record processed */
|
||||
unsigned long time; /* time record first logged */
|
||||
@@ -62,17 +64,17 @@ struct EP_LIST {
|
||||
|
||||
/*
|
||||
* Structure for stack of lock sets that
|
||||
* currently contain breakpoints. (uses lstLib)
|
||||
* currently contain breakpoints. (uses ellLib)
|
||||
*/
|
||||
struct LS_LIST {
|
||||
NODE *next_list;
|
||||
NODE *prev_list;
|
||||
ELLNODE *next_list;
|
||||
ELLNODE *prev_list;
|
||||
struct dbCommon *precord;/* points to where execution is currently stopped */
|
||||
struct dbCommon *current_ep; /* current entrypoint */
|
||||
LIST bp_list; /* list of records containing breakpoints in a lockset */
|
||||
LIST ep_queue; /* queue of entrypoints found so far */
|
||||
SEM_ID ex_sem; /* semaphore for execution queue */
|
||||
int taskid; /* saved taskid for the task in stepping mode */
|
||||
ELLLIST bp_list; /* list of records containing breakpoints in a lockset */
|
||||
ELLLIST ep_queue; /* queue of entrypoints found so far */
|
||||
semId ex_sem; /* semaphore for execution queue */
|
||||
threadId taskid; /* saved taskid for the task in stepping mode */
|
||||
int step; /* one if currently "stepping," else zero */
|
||||
unsigned long l_num; /* lockset number */
|
||||
};
|
||||
|
||||
119
src/db/dbCa.c
119
src/db/dbCa.c
@@ -24,21 +24,21 @@ of this distribution.
|
||||
* .01 26MAR96 lrd rewritten for simplicity, robustness and flexibility
|
||||
****************************************************************/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "osiSem.h"
|
||||
#include "osiThread.h"
|
||||
#include "errlog.h"
|
||||
#include "cadef.h"
|
||||
#include "caerr.h"
|
||||
#include "alarm.h"
|
||||
#include "db_access.h"
|
||||
#include "link.h"
|
||||
#include "task_params.h"
|
||||
#include "errMdef.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbCommon.h"
|
||||
@@ -48,8 +48,8 @@ void scanOnce(void *precord);
|
||||
extern volatile int interruptAccept;
|
||||
|
||||
static ELLLIST caList; /* Work list for dbCaTask */
|
||||
static SEM_ID caListSem; /*Mutual exclusions semaphores for caList*/
|
||||
static SEM_ID caWakeupSem; /*wakeup semaphore for dbCaTask*/
|
||||
static semId caListSem; /*Mutual exclusions semaphores for caList*/
|
||||
static semId caWakeupSem; /*wakeup semaphore for dbCaTask*/
|
||||
void dbCaTask(void); /*The Channel Access Task*/
|
||||
|
||||
/* caLink locking
|
||||
@@ -66,26 +66,25 @@ static void addAction(caLink *pca, short link_action)
|
||||
{
|
||||
int callAdd = FALSE;
|
||||
|
||||
semTake(caListSem,WAIT_FOREVER);
|
||||
semMutexTakeAssert(caListSem);
|
||||
if(pca->link_action==0) callAdd = TRUE;
|
||||
pca->link_action |= link_action;
|
||||
if(callAdd) ellAdd(&caList,&pca->node);
|
||||
semGive(caListSem);
|
||||
if(callAdd) semGive(caWakeupSem);
|
||||
semMutexGive(caListSem);
|
||||
if(callAdd) semBinaryGive(caWakeupSem);
|
||||
}
|
||||
|
||||
void dbCaLinkInit(void)
|
||||
{
|
||||
ellInit(&caList);
|
||||
caListSem = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY);
|
||||
caWakeupSem = semBCreate(SEM_Q_PRIORITY,SEM_EMPTY);
|
||||
caListSem = semMutexCreate();
|
||||
caWakeupSem = semBinaryCreate(semEmpty);
|
||||
if(!caListSem || !caWakeupSem) {
|
||||
printf("dbCaLinkInit: semBCreate failed\n");
|
||||
return;
|
||||
}
|
||||
taskSpawn("dbCaLink", DB_CA_PRI, DB_CA_OPT,
|
||||
DB_CA_STACK, (FUNCPTR) dbCaTask,
|
||||
0,0,0,0,0,0,0,0,0,0);
|
||||
threadCreate("dbCaLink", threadPriorityMedium,
|
||||
threadGetStackSize(threadStackBig), (THREADFUNC) dbCaTask,0);
|
||||
}
|
||||
|
||||
void dbCaAddLink( struct link *plink)
|
||||
@@ -96,9 +95,9 @@ void dbCaAddLink( struct link *plink)
|
||||
pca->plink = plink;
|
||||
plink->type = CA_LINK;
|
||||
plink->value.pv_link.pvt = pca;
|
||||
if((pca->lock = semBCreate(SEM_Q_PRIORITY,SEM_FULL)) == NULL){
|
||||
printf("dbCaAddLink: semBCreate failed\n");
|
||||
taskSuspend(0);
|
||||
if((pca->lock = semMutexCreate()) == 0){
|
||||
printf("dbCaAddLink: semMutexCreate failed\n");
|
||||
threadSuspend(threadGetIdSelf());
|
||||
}
|
||||
addAction(pca,CA_CONNECT);
|
||||
return;
|
||||
@@ -107,17 +106,12 @@ void dbCaAddLink( struct link *plink)
|
||||
void dbCaRemoveLink( struct link *plink)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
STATUS semStatus;
|
||||
|
||||
if(!pca) return;
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCaRemoveLink: semStatus!OK\n");
|
||||
return;
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
pca->plink = 0;
|
||||
plink->value.pv_link.pvt = 0;
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
addAction(pca,CA_DELETE);
|
||||
}
|
||||
|
||||
@@ -128,7 +122,6 @@ long dbCaGetLink(struct link *plink,short dbrType, char *pdest,
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
long status = 0;
|
||||
long (*pconvert)();
|
||||
STATUS semStatus;
|
||||
short link_action = 0;
|
||||
|
||||
if(!pca) {
|
||||
@@ -136,11 +129,7 @@ long dbCaGetLink(struct link *plink,short dbrType, char *pdest,
|
||||
plink->value.pv_link.precord);
|
||||
return(-1);
|
||||
}
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCaGetLink: semStatus!OK\n");
|
||||
return(-1);
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
if(!pca->chid || ca_state(pca->chid) != cs_conn) {
|
||||
pca->sevr = INVALID_ALARM;
|
||||
goto done;
|
||||
@@ -192,7 +181,7 @@ long dbCaGetLink(struct link *plink,short dbrType, char *pdest,
|
||||
}
|
||||
done:
|
||||
if(psevr) *psevr = pca->sevr;
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
if(link_action) addAction(pca,link_action);
|
||||
return(status);
|
||||
}
|
||||
@@ -203,7 +192,6 @@ long dbCaPutLink(struct link *plink,short dbrType,
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
long (*pconvert)();
|
||||
long status = 0;
|
||||
STATUS semStatus;
|
||||
short link_action = 0;
|
||||
|
||||
if(!pca) {
|
||||
@@ -212,13 +200,9 @@ long dbCaPutLink(struct link *plink,short dbrType,
|
||||
return(-1);
|
||||
}
|
||||
/* put the new value in */
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCaGetLink: semStatus!OK\n");
|
||||
return(-1);
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
if(!pca->chid || ca_state(pca->chid) != cs_conn) {
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
return(-1);
|
||||
}
|
||||
if((pca->dbrType == DBR_ENUM) && (dbDBRnewToDBRold[dbrType] == DBR_STRING)){
|
||||
@@ -258,7 +242,7 @@ long dbCaPutLink(struct link *plink,short dbrType,
|
||||
if(pca->newOutNative) pca->nNoWrite++;
|
||||
pca->newOutNative = TRUE;
|
||||
}
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
addAction(pca,link_action);
|
||||
return(status);
|
||||
}
|
||||
@@ -268,7 +252,6 @@ long dbCaGetAttributes(struct link *plink,
|
||||
{
|
||||
caLink *pca;
|
||||
long status = 0;
|
||||
STATUS semStatus;
|
||||
short link_action = 0;
|
||||
caAttributes *pcaAttributes;
|
||||
|
||||
@@ -290,14 +273,10 @@ long dbCaGetAttributes(struct link *plink,
|
||||
pcaAttributes = dbCalloc(1,sizeof(caAttributes));
|
||||
pcaAttributes->callback = callback;
|
||||
pcaAttributes->usrPvt = usrPvt;
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCaGetLink: semStatus!OK\n");
|
||||
return(-1);
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
pca->pcaAttributes = pcaAttributes;
|
||||
link_action |= CA_GET_ATTRIBUTES;
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
addAction(pca,link_action);
|
||||
return(status);
|
||||
}
|
||||
@@ -437,7 +416,6 @@ static void eventCallback(struct event_handler_args arg)
|
||||
caLink *pca = (caLink *)arg.usr;
|
||||
struct link *plink;
|
||||
long size;
|
||||
STATUS semStatus;
|
||||
dbCommon *precord = 0;
|
||||
struct dbr_time_double *pdbr_time_double;
|
||||
|
||||
@@ -445,11 +423,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
epicsPrintf("eventCallback why was arg.usr NULL\n");
|
||||
return;
|
||||
}
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCa eventTask: semStatus!OK\n");
|
||||
return;
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
plink = pca->plink;
|
||||
if(!plink) goto done;
|
||||
precord = (dbCommon *)plink->value.pv_link.precord;
|
||||
@@ -498,14 +472,13 @@ static void eventCallback(struct event_handler_args arg)
|
||||
scanOnce(precord);
|
||||
}
|
||||
done:
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
}
|
||||
|
||||
static void getAttribEventCallback(struct event_handler_args arg)
|
||||
{
|
||||
caLink *pca = (caLink *)arg.usr;
|
||||
struct link *plink;
|
||||
STATUS semStatus;
|
||||
const struct dbr_ctrl_double *dbr;
|
||||
caAttributes *pcaAttributes = NULL;
|
||||
|
||||
@@ -513,11 +486,7 @@ const struct dbr_ctrl_double *dbr;
|
||||
epicsPrintf("getAttribEventCallback why was arg.usr NULL\n");
|
||||
return;
|
||||
}
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("getAttribEventCallback: semStatus!OK\n");
|
||||
return;
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
plink = pca->plink;
|
||||
if(!plink) goto done;
|
||||
if(!arg.dbr) {
|
||||
@@ -531,25 +500,20 @@ const struct dbr_ctrl_double *dbr;
|
||||
pcaAttributes->gotData = TRUE;
|
||||
(pcaAttributes->callback)(pcaAttributes->usrPvt);
|
||||
done:
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
}
|
||||
|
||||
static void accessRightsCallback(struct access_rights_handler_args arg)
|
||||
{
|
||||
caLink *pca = (caLink *)ca_puser(arg.chid);
|
||||
struct link *plink;
|
||||
STATUS semStatus;
|
||||
|
||||
if(!pca) {
|
||||
epicsPrintf("accessRightsCallback why was arg.usr NULL\n");
|
||||
return;
|
||||
}
|
||||
if(ca_state(pca->chid) != cs_conn) return;/*connectionCallback will handle*/
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCa accessRightsCallback: semStatus!OK\n");
|
||||
return;
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
if(ca_read_access(arg.chid) || ca_write_access(arg.chid)) goto done;
|
||||
plink = pca->plink;
|
||||
if(plink) {
|
||||
@@ -563,7 +527,7 @@ static void accessRightsCallback(struct access_rights_handler_args arg)
|
||||
}
|
||||
}
|
||||
done:
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
}
|
||||
|
||||
static void connectionCallback(struct connection_handler_args arg)
|
||||
@@ -571,15 +535,10 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
caLink *pca;
|
||||
short link_action = 0;
|
||||
struct link *plink;
|
||||
STATUS semStatus;
|
||||
|
||||
pca = ca_puser(arg.chid);
|
||||
if(!pca) return;
|
||||
semStatus = semTake(pca->lock,WAIT_FOREVER);
|
||||
if(semStatus!=OK) {
|
||||
epicsPrintf("dbCa connectionCallback: semStatus!OK\n");
|
||||
return;
|
||||
}
|
||||
semMutexTakeAssert(pca->lock);
|
||||
plink = pca->plink;
|
||||
if(!plink) goto done;
|
||||
if(ca_state(arg.chid) != cs_conn){
|
||||
@@ -601,7 +560,7 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
/*Only safe thing is to delete old caLink and allocate a new one*/
|
||||
pca->plink = 0;
|
||||
plink->value.pv_link.pvt = 0;
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
addAction(pca,CA_DELETE);
|
||||
dbCaAddLink(plink);
|
||||
return;
|
||||
@@ -624,7 +583,7 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
}
|
||||
if(pca->pcaAttributes) link_action |= CA_GET_ATTRIBUTES;
|
||||
done:
|
||||
semGive(pca->lock);
|
||||
semMutexGive(pca->lock);
|
||||
if(link_action) addAction(pca,link_action);
|
||||
}
|
||||
|
||||
@@ -636,17 +595,17 @@ void dbCaTask()
|
||||
|
||||
SEVCHK(ca_task_initialize(),NULL);
|
||||
/*Dont do anything until iocInit initializes database*/
|
||||
while(!interruptAccept) taskDelay(10);
|
||||
while(!interruptAccept) threadSleep(.1);
|
||||
/* channel access event loop */
|
||||
while (TRUE){
|
||||
semTake(caWakeupSem,WAIT_FOREVER);
|
||||
semBinaryTakeAssert(caWakeupSem);
|
||||
while(TRUE) { /* process all requests in caList*/
|
||||
semTake(caListSem,WAIT_FOREVER);
|
||||
semMutexTakeAssert(caListSem);
|
||||
if((pca = (caLink *)ellFirst(&caList))){/*Take off list head*/
|
||||
ellDelete(&caList,&pca->node);
|
||||
link_action = pca->link_action;
|
||||
pca->link_action = 0;
|
||||
semGive(caListSem); /*Give it back immediately*/
|
||||
semMutexGive(caListSem); /*Give it back immediately*/
|
||||
if(link_action&CA_DELETE) {/*This must be first*/
|
||||
if(pca->chid) ca_clear_channel(pca->chid);
|
||||
free(pca->pgetNative);
|
||||
@@ -654,7 +613,7 @@ void dbCaTask()
|
||||
free(pca->pgetString);
|
||||
free(pca->pputString);
|
||||
free(pca->pcaAttributes);
|
||||
semDelete(pca->lock);
|
||||
semMutexDestroy(pca->lock);
|
||||
free(pca);
|
||||
continue; /*No other link_action makes sense*/
|
||||
}
|
||||
@@ -719,7 +678,7 @@ void dbCaTask()
|
||||
ca_message(status));
|
||||
}
|
||||
} else { /* caList was empty */
|
||||
semGive(caListSem);
|
||||
semMutexGive(caListSem);
|
||||
break; /*caList is empty*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ typedef struct caLink
|
||||
char *pputString;
|
||||
caAttributes *pcaAttributes;
|
||||
long nelements;
|
||||
SEM_ID lock;
|
||||
semId lock;
|
||||
unsigned long nDisconnect;
|
||||
unsigned long nNoWrite;
|
||||
short dbrType;
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
prompt("Monitor fastlock")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("FAST_LOCK mlok")
|
||||
extra("semId mlok")
|
||||
}
|
||||
field(MLIS,DBF_NOACCESS) {
|
||||
prompt("Monitor List")
|
||||
|
||||
@@ -3,49 +3,31 @@
|
||||
* Original Author: Bob Dalesio
|
||||
* Current Author: Marty Kraimer
|
||||
* Date: 11-7-90
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 11OCT95 mrk Moved from dbLink.c
|
||||
*/
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
*/
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "cvtFast.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
/********************COPYRIGHT NOTIFICATION**********************************
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
****************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "cvtFast.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
|
||||
/* DATABASE ACCESS GET CONVERSION SUPPORT */
|
||||
|
||||
|
||||
261
src/db/dbEvent.c
261
src/db/dbEvent.c
@@ -4,31 +4,21 @@
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
* Date: 4-1-89
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* Modification Log:
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1991 Regents of the University of California,
|
||||
and the University of Chicago Board of Governors.
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_Combined file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
/* Modification Log:
|
||||
* -----------------
|
||||
* joh 00 04xx89 Created
|
||||
* joh 01 043089 Init Release
|
||||
@@ -64,42 +54,35 @@
|
||||
* problem
|
||||
*/
|
||||
|
||||
#include "epicsAssert.h"
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <wdLib.h>
|
||||
#include <semLib.h>
|
||||
#include <stdioLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <ellLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <string.h>
|
||||
#include <logLib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "taskwd.h"
|
||||
#include "freeList.h"
|
||||
#include "tsDefs.h"
|
||||
#include "dbCommon.h"
|
||||
#include "task_params.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbEvent.h"
|
||||
#include "caeventmask.h"
|
||||
|
||||
#include "memDebugLib.h"
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "cantProceed.h"
|
||||
#include "dbDefs.h"
|
||||
#include "osiSem.h"
|
||||
#include "osiThread.h"
|
||||
#include "osiClock.h"
|
||||
#include "errlog.h"
|
||||
#include "taskwd.h"
|
||||
#include "freeList.h"
|
||||
#include "tsDefs.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbEvent.h"
|
||||
#include "caeventmask.h"
|
||||
|
||||
/* local function declarations */
|
||||
|
||||
LOCAL int event_read(struct event_que *ev_que);
|
||||
|
||||
LOCAL int db_post_single_event_private(struct event_block *event);
|
||||
|
||||
/* what to do with unrecoverable errors */
|
||||
#define abort(S) taskSuspend((int)taskIdCurrent);
|
||||
#define abort(S) cantProceed("dbEvent abort")
|
||||
|
||||
/*
|
||||
* Reliable intertask communication requires copying the current value of the
|
||||
@@ -123,20 +106,22 @@ LOCAL int db_post_single_event_private(struct event_block *event);
|
||||
)
|
||||
|
||||
#define LOCKEVQUE(EV_QUE)\
|
||||
FASTLOCK(&(EV_QUE)->writelock);
|
||||
semMutexTakeAssert((EV_QUE)->writelock);
|
||||
|
||||
#define UNLOCKEVQUE(EV_QUE)\
|
||||
FASTUNLOCK(&(EV_QUE)->writelock);
|
||||
semMutexGive((EV_QUE)->writelock);
|
||||
|
||||
#define LOCKREC(RECPTR)\
|
||||
FASTLOCK(&(RECPTR)->mlok);
|
||||
semMutexTakeAssert((RECPTR)->mlok);
|
||||
|
||||
#define UNLOCKREC(RECPTR)\
|
||||
FASTUNLOCK(&(RECPTR)->mlok);
|
||||
semMutexGive((RECPTR)->mlok);
|
||||
|
||||
LOCAL void *dbevEventUserFreeList;
|
||||
LOCAL void *dbevEventQueueFreeList;
|
||||
|
||||
static char *EVENT_PEND_NAME = "event task";
|
||||
|
||||
|
||||
/*
|
||||
* DB_EVENT_LIST()
|
||||
@@ -170,7 +155,7 @@ int db_event_list(char *name)
|
||||
printf(" ev user %lx\n", (unsigned long) pevent->ev_que->evUser);
|
||||
printf("ring space %u\n", RNGSPACE(pevent->ev_que));
|
||||
#endif
|
||||
printf( "task %x select %x pfield %lx behind by %ld\n",
|
||||
printf( "task %p select %x pfield %lx behind by %ld\n",
|
||||
pevent->ev_que->evUser->taskid,
|
||||
pevent->select,
|
||||
(unsigned long) pevent->paddr->pfield,
|
||||
@@ -210,17 +195,17 @@ struct event_user *db_init_events(void)
|
||||
return NULL;
|
||||
|
||||
evUser->firstque.evUser = evUser;
|
||||
FASTLOCKINIT(&(evUser->firstque.writelock));
|
||||
evUser->ppendsem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
|
||||
evUser->firstque.writelock = semMutexCreate();
|
||||
evUser->ppendsem = semBinaryCreate(semEmpty);
|
||||
if(!evUser->ppendsem){
|
||||
FASTLOCKFREE(&(evUser->firstque.writelock));
|
||||
semMutexDestroy(evUser->firstque.writelock);
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
return NULL;
|
||||
}
|
||||
evUser->pflush_sem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY);
|
||||
evUser->pflush_sem = semBinaryCreate(semEmpty);
|
||||
if(!evUser->pflush_sem){
|
||||
FASTLOCKFREE(&(evUser->firstque.writelock));
|
||||
semDelete(evUser->ppendsem);
|
||||
semMutexDestroy(evUser->firstque.writelock);
|
||||
semBinaryDestroy(evUser->ppendsem);
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
return NULL;
|
||||
}
|
||||
@@ -253,7 +238,7 @@ int db_close_events(struct event_user *evUser)
|
||||
evUser->pendexit = TRUE;
|
||||
|
||||
/* notify the waiting task */
|
||||
semGive(evUser->ppendsem);
|
||||
semBinaryGive(evUser->ppendsem);
|
||||
|
||||
|
||||
return OK;
|
||||
@@ -319,7 +304,7 @@ struct event_block *pevent /* ptr to event blk (not required) */
|
||||
if(!tmp_que)
|
||||
return ERROR;
|
||||
tmp_que->evUser = evUser;
|
||||
FASTLOCKINIT(&(tmp_que->writelock));
|
||||
tmp_que->writelock = semMutexCreate();
|
||||
ev_que->nextque = tmp_que;
|
||||
ev_que = tmp_que;
|
||||
break;
|
||||
@@ -455,7 +440,7 @@ int db_cancel_event(struct event_block *pevent)
|
||||
pevent->user_sub = NULL;
|
||||
while (pevent->npend || pevent->callBackInProgress) {
|
||||
UNLOCKEVQUE(pevent->ev_que)
|
||||
semTake(pevent->ev_que->evUser->pflush_sem, sysClkRateGet());
|
||||
semBinaryTakeTimeout(pevent->ev_que->evUser->pflush_sem, 1.0);
|
||||
LOCKEVQUE(pevent->ev_que)
|
||||
}
|
||||
UNLOCKEVQUE(pevent->ev_que)
|
||||
@@ -498,7 +483,7 @@ struct event_user *evUser
|
||||
)
|
||||
{
|
||||
while(evUser->extra_labor){
|
||||
taskDelay(sysClkRateGet());
|
||||
threadSleep(1.0);
|
||||
}
|
||||
|
||||
return OK;
|
||||
@@ -530,13 +515,9 @@ void *arg
|
||||
*/
|
||||
int db_post_extra_labor(struct event_user *evUser)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* notify the event handler of extra labor */
|
||||
evUser->extra_labor = TRUE;
|
||||
status = semGive(evUser->ppendsem);
|
||||
assert(status == OK);
|
||||
|
||||
semBinaryGive(evUser->ppendsem);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -715,7 +696,7 @@ LOCAL int db_post_single_event_private(struct event_block *event)
|
||||
/*
|
||||
* notify the event handler
|
||||
*/
|
||||
semGive(ev_que->evUser->ppendsem);
|
||||
semBinaryGive(ev_que->evUser->ppendsem);
|
||||
}
|
||||
|
||||
if (pLog) {
|
||||
@@ -739,39 +720,28 @@ int init_func_arg,
|
||||
int priority_offset
|
||||
)
|
||||
{
|
||||
int status;
|
||||
int taskpri;
|
||||
int firstTry;
|
||||
|
||||
/* only one ca_pend_event thread may be started for each evUser ! */
|
||||
while(!vxTas(&evUser->pendlck))
|
||||
return ERROR;
|
||||
|
||||
status = taskPriorityGet(taskIdSelf(), &taskpri);
|
||||
if(status == ERROR)
|
||||
return ERROR;
|
||||
|
||||
threadLockContextSwitch();
|
||||
if(evUser->pendlck==0) {
|
||||
firstTry = TRUE;
|
||||
++evUser->pendlck ;
|
||||
} else {
|
||||
firstTry = FALSE;
|
||||
}
|
||||
threadUnlockContextSwitch();
|
||||
if(!firstTry) return ERROR;
|
||||
taskpri = threadGetPriority(threadGetIdSelf());
|
||||
taskpri += priority_offset;
|
||||
|
||||
evUser->pendexit = FALSE;
|
||||
|
||||
if(!taskname)
|
||||
taskname = EVENT_PEND_NAME;
|
||||
status =
|
||||
taskSpawn(
|
||||
taskname,
|
||||
taskpri,
|
||||
EVENT_PEND_OPT,
|
||||
EVENT_PEND_STACK,
|
||||
event_task,
|
||||
(int)evUser,
|
||||
(int)init_func,
|
||||
(int)init_func_arg,
|
||||
0,0,0,0,0,0,0);
|
||||
if(status == ERROR)
|
||||
return ERROR;
|
||||
|
||||
evUser->taskid = status;
|
||||
|
||||
evUser->init_func = init_func;
|
||||
evUser->init_func_arg = init_func_arg;
|
||||
if(!taskname) taskname = EVENT_PEND_NAME;
|
||||
evUser->taskid = threadCreate(
|
||||
taskname,taskpri,threadGetStackSize(threadStackMedium),
|
||||
(THREADFUNC)event_task,(void *)evUser);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -781,35 +751,25 @@ int priority_offset
|
||||
* EVENT_TASK()
|
||||
*
|
||||
*/
|
||||
int event_task(
|
||||
struct event_user *evUser,
|
||||
int (*init_func)(),
|
||||
int init_func_arg
|
||||
)
|
||||
void event_task( struct event_user *evUser)
|
||||
{
|
||||
int status;
|
||||
struct event_que *ev_que;
|
||||
|
||||
/* init hook */
|
||||
if (init_func) {
|
||||
status = (*init_func)(init_func_arg);
|
||||
if (evUser->init_func) {
|
||||
status = (*evUser->init_func)(evUser->init_func_arg);
|
||||
if (status!=OK) {
|
||||
logMsg("Unable to intialize the event system!\n",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
semGive(evUser->ppendsem);
|
||||
errlogPrintf("Unable to intialize the event system!\n");
|
||||
semBinaryGive(evUser->ppendsem);
|
||||
evUser->pendexit = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
taskwdInsert((int)taskIdCurrent,NULL,NULL);
|
||||
taskwdInsert(threadGetIdSelf(),NULL,NULL);
|
||||
|
||||
do{
|
||||
semTake(evUser->ppendsem, WAIT_FOREVER);
|
||||
semBinaryTakeAssert(evUser->ppendsem);
|
||||
|
||||
/*
|
||||
* check to see if the caller has offloaded
|
||||
@@ -830,7 +790,6 @@ int init_func_arg
|
||||
for( ev_que= &evUser->firstque;
|
||||
ev_que;
|
||||
ev_que = ev_que->nextque){
|
||||
|
||||
event_read(ev_que);
|
||||
}
|
||||
|
||||
@@ -844,13 +803,8 @@ int init_func_arg
|
||||
evUser->overflow_arg,
|
||||
evUser->queovr);
|
||||
else
|
||||
logMsg("Events lost, discard count was %d\n",
|
||||
evUser->queovr,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
errlogPrintf("Events lost, discard count was %d\n",
|
||||
evUser->queovr);
|
||||
evUser->queovr = 0;
|
||||
}
|
||||
}
|
||||
@@ -859,14 +813,7 @@ int init_func_arg
|
||||
|
||||
evUser->pendlck = FALSE;
|
||||
|
||||
if(FASTLOCKFREE(&evUser->firstque.writelock)<0)
|
||||
logMsg("evtsk: fast lock free fail 1\n",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
semMutexDestroy(evUser->firstque.writelock);
|
||||
|
||||
/* joh- added this code to free additional event queues */
|
||||
{
|
||||
@@ -876,45 +823,20 @@ int init_func_arg
|
||||
while(ev_que){
|
||||
|
||||
nextque = ev_que->nextque;
|
||||
if(FASTLOCKFREE(&ev_que->writelock)<0)
|
||||
logMsg("evtsk: fast lock free fail 2\n",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
semMutexDestroy(ev_que->writelock);
|
||||
freeListFree(dbevEventQueueFreeList, ev_que);
|
||||
ev_que = nextque;
|
||||
}
|
||||
}
|
||||
|
||||
status = semDelete(evUser->ppendsem);
|
||||
if(status != OK){
|
||||
logMsg("evtsk: sem delete fail at exit\n",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
status = semDelete(evUser->pflush_sem);
|
||||
if(status != OK){
|
||||
logMsg("evtsk: flush sem delete fail at exit\n",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
semBinaryDestroy(evUser->ppendsem);
|
||||
semBinaryDestroy(evUser->pflush_sem);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
|
||||
taskwdRemove((int)taskIdCurrent);
|
||||
taskwdRemove(threadGetIdSelf());
|
||||
|
||||
return OK;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -929,7 +851,6 @@ LOCAL int event_read (struct event_que *ev_que)
|
||||
db_field_log *pfl;
|
||||
void (*user_sub) (void *user_arg, struct dbAddr *paddr,
|
||||
int eventsRemaining, db_field_log *pfl);
|
||||
int status;
|
||||
|
||||
/*
|
||||
* evUser ring buffer must be locked for the multiple
|
||||
@@ -1027,11 +948,7 @@ LOCAL int event_read (struct event_que *ev_que)
|
||||
* queue
|
||||
*/
|
||||
if (event->user_sub==NULL && event->npend==0u) {
|
||||
status = semGive (ev_que->evUser->pflush_sem);
|
||||
if (status!=OK) {
|
||||
epicsPrintf ("%s.%d corrupt flush sem\n",
|
||||
__FILE__, __LINE__);
|
||||
}
|
||||
semBinaryGive (ev_que->evUser->pflush_sem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1049,7 +966,7 @@ void db_event_flow_ctrl_mode_on (struct event_user *evUser)
|
||||
/*
|
||||
* notify the event handler task
|
||||
*/
|
||||
semGive (evUser->ppendsem);
|
||||
semBinaryGive(evUser->ppendsem);
|
||||
#ifdef DEBUG
|
||||
printf("fc on %lu\n", tickGet());
|
||||
#endif
|
||||
@@ -1064,7 +981,7 @@ void db_event_flow_ctrl_mode_off (struct event_user *evUser)
|
||||
/*
|
||||
* notify the event handler task
|
||||
*/
|
||||
semGive (evUser->ppendsem);
|
||||
semBinaryGive (evUser->ppendsem);
|
||||
#ifdef DEBUG
|
||||
printf("fc off %lu\n", tickGet());
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#endif /*caClient*/
|
||||
|
||||
#include <db_field_log.h>
|
||||
#include <osiThread.h>
|
||||
|
||||
struct event_block{
|
||||
ELLNODE node;
|
||||
@@ -78,7 +79,7 @@ typedef void EVENTFUNC(
|
||||
struct event_que{
|
||||
/* lock writers to the ring buffer only */
|
||||
/* readers must never slow up writers */
|
||||
FAST_LOCK writelock;
|
||||
semId writelock;
|
||||
db_field_log valque[EVENTQUESIZE];
|
||||
struct event_block *evque[EVENTQUESIZE];
|
||||
struct event_que *nextque; /* in case que quota exceeded */
|
||||
@@ -91,8 +92,8 @@ struct event_que{
|
||||
struct event_user{
|
||||
struct event_que firstque; /* the first event que */
|
||||
|
||||
SEM_ID ppendsem; /* Wait while empty */
|
||||
SEM_ID pflush_sem; /* wait for flush */
|
||||
semId ppendsem; /* Wait while empty */
|
||||
semId pflush_sem; /* wait for flush */
|
||||
|
||||
void (*overflow_sub)(/* called when overflow detect */
|
||||
void *overflow_arg, unsigned count);
|
||||
@@ -102,13 +103,15 @@ struct event_user{
|
||||
(void *extralabor_arg);
|
||||
void *extralabor_arg;/* parameter to above */
|
||||
|
||||
int taskid; /* event handler task id */
|
||||
threadId taskid; /* event handler task id */
|
||||
unsigned queovr; /* event que overflow count */
|
||||
unsigned nDuplicates; /* events duplicated on q */
|
||||
char pendlck; /* Only one task can pend */
|
||||
unsigned char pendexit; /* exit pend task */
|
||||
unsigned char extra_labor; /* if set call extra labor func */
|
||||
unsigned char flowCtrlMode; /* replace existing monitor */
|
||||
int (*init_func)();
|
||||
int init_func_arg;
|
||||
};
|
||||
|
||||
typedef void OVRFFUNC(void *overflow_arg, unsigned count);
|
||||
@@ -163,11 +166,7 @@ int init_func_arg,
|
||||
int priority_offset
|
||||
);
|
||||
|
||||
int event_task(
|
||||
struct event_user *evUser,
|
||||
int (*init_func)(int),
|
||||
int init_func_arg
|
||||
);
|
||||
void event_task( struct event_user *evUser);
|
||||
|
||||
int db_event_enable(struct event_block *pevent);
|
||||
int db_event_disable(struct event_block *pevent);
|
||||
|
||||
@@ -28,35 +28,26 @@
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
*/
|
||||
#include <vxWorks.h>
|
||||
#include <lstLib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <taskLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "cvtFast.h"
|
||||
#include "alarm.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "fast_lock.h"
|
||||
#include "cvtFast.h"
|
||||
#include "alarm.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "db_field_log.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "special.h"
|
||||
|
||||
extern struct dbBase *pdbbase;
|
||||
|
||||
/*
|
||||
* In the following functions:
|
||||
|
||||
161
src/db/dbLock.c
161
src/db/dbLock.c
@@ -19,15 +19,15 @@ of this distribution.
|
||||
|
||||
/************** DISCUSSION OF DYNAMIC LINK MODIFICATION **********************
|
||||
|
||||
Since the purpose of lock sets is to prevent multiple tasks from simultaneously
|
||||
Since the purpose of lock sets is to prevent multiple thread from simultaneously
|
||||
accessing records in set, dynamically changing lock sets presents a problem.
|
||||
|
||||
Four problems arise:
|
||||
|
||||
1) Two tasks simultaneoulsy trying to change lock sets
|
||||
2) Another task has successfully issued a dbScanLock and currently owns it.
|
||||
3) A task is waiting for dbScanLock.
|
||||
4) While lock set is being changed, a task issues a dbScanLock.
|
||||
1) Two threads simultaneoulsy trying to change lock sets
|
||||
2) Another thread has successfully issued a dbScanLock and currently owns it.
|
||||
3) A thread is waiting for dbScanLock.
|
||||
4) While lock set is being changed, a thread issues a dbScanLock.
|
||||
|
||||
Solution:
|
||||
|
||||
@@ -45,59 +45,57 @@ Each problem above is solved as follows:
|
||||
1) dbLockGlobal solves this problem.
|
||||
2) dbLockSetRecordLock solves this problem.
|
||||
3) After changing lock sets original semId id deleted.
|
||||
This makes all tasks in semTake for that semaphore fail.
|
||||
The code in dbScanLock makes task recover.
|
||||
This makes all threads in semTake for that semaphore fail.
|
||||
The code in dbScanLock makes thread recover.
|
||||
4) The global variable changingLockSets and code in
|
||||
dbScanLock and semFlush in dbLockSetGblUnlock solves
|
||||
this problem.
|
||||
|
||||
Note that all other tasks are prevented from processing records between
|
||||
Note that all other threads are prevented from processing records between
|
||||
dbLockSetGblLock and dbLockSetGblUnlock.
|
||||
|
||||
dblsr may crash if executed while lock sets are being modified.
|
||||
It is NOT a good idea to make it more robust by issuing dbLockSetGblLock
|
||||
since this will delay all other tasks.
|
||||
since this will delay all other threads.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <lstLib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <semLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "dbBase.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "errMdef.h"
|
||||
#include "dbDefs.h"
|
||||
#include "dbBase.h"
|
||||
#include "osiSem.h"
|
||||
#include "osiClock.h"
|
||||
#include "osiThread.h"
|
||||
#include "cantProceed.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "errMdef.h"
|
||||
|
||||
#define STATIC static
|
||||
|
||||
STATIC int lockListInitialized = FALSE;
|
||||
|
||||
STATIC ELLLIST lockList;
|
||||
STATIC SEM_ID globalLockSemId;
|
||||
STATIC SEM_ID globalWaitSemid;
|
||||
STATIC semId globalLock;
|
||||
STATIC semId globalWait;
|
||||
STATIC unsigned long id = 0;
|
||||
STATIC int changingLockSets = FALSE;
|
||||
|
||||
typedef struct lockSet {
|
||||
ELLNODE node;
|
||||
ELLLIST recordList;
|
||||
SEM_ID semId;
|
||||
ULONG start_time;
|
||||
int task_id;
|
||||
semId lock;
|
||||
unsigned long start_time;
|
||||
threadId thread_id;
|
||||
dbCommon *precord;
|
||||
unsigned long id;
|
||||
} lockSet;
|
||||
@@ -107,19 +105,16 @@ typedef struct lockRecord {
|
||||
lockSet *plockSet;
|
||||
dbCommon *precord;
|
||||
} lockRecord;
|
||||
#define semMCoptions SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY
|
||||
|
||||
/*private routines */
|
||||
STATIC void initLockList(void)
|
||||
{
|
||||
ellInit(&lockList);
|
||||
if((globalLockSemId = semMCreate(semMCoptions))==0) {
|
||||
errMessage(0,"allocLockNode called semMCreate\n");
|
||||
exit(-1);
|
||||
if((globalLock = semMutexCreate())==0) {
|
||||
cantProceed("initLockList failed calling semMutexCreate\n");
|
||||
}
|
||||
if((globalWaitSemid = semBCreate(SEM_Q_FIFO,SEM_EMPTY))==0) {
|
||||
errMessage(0,"allocLockNode called semBCreate\n");
|
||||
exit(-1);
|
||||
if((globalWait = semBinaryCreate(semEmpty))==0) {
|
||||
cantProceed("initLockList failed calling semBinaryCreate\n");
|
||||
}
|
||||
lockListInitialized = TRUE;
|
||||
}
|
||||
@@ -136,9 +131,8 @@ STATIC lockSet * allocLock(lockRecord *plockRecord)
|
||||
plockSet->id = id;
|
||||
ellAdd(&plockSet->recordList,&plockRecord->node);
|
||||
ellAdd(&lockList,&plockSet->node);
|
||||
if((plockSet->semId = semMCreate(semMCoptions))==0) {
|
||||
errMessage(0,"allocLockNode called semMCreate\n");
|
||||
exit(-1);
|
||||
if((plockSet->lock = semMutexCreate())==0) {
|
||||
cantProceed("allocLock calling semMutexCreate\n");
|
||||
}
|
||||
return(plockSet);
|
||||
}
|
||||
@@ -152,24 +146,18 @@ STATIC void lockAddRecord(lockSet *plockSet,lockRecord *pnew)
|
||||
|
||||
void dbLockSetGblLock(void)
|
||||
{
|
||||
STATUS status;
|
||||
|
||||
if(!lockListInitialized) initLockList();
|
||||
status = semTake(globalLockSemId,WAIT_FOREVER);
|
||||
if(status!=OK) {
|
||||
epicsPrintf("dbLockSetGblLock failure\n");
|
||||
taskSuspend(0);
|
||||
}
|
||||
semMutexTakeAssert(globalLock);
|
||||
changingLockSets = TRUE;
|
||||
}
|
||||
|
||||
void dbLockSetGblUnlock(void)
|
||||
{
|
||||
taskLock();
|
||||
threadLockContextSwitch();
|
||||
changingLockSets = FALSE;
|
||||
semFlush(globalWaitSemid);
|
||||
taskUnlock();
|
||||
semGive(globalLockSemId);
|
||||
semBinaryFlush(globalWait);
|
||||
threadUnlockContextSwitch();
|
||||
semMutexGive(globalLock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,32 +165,31 @@ void dbLockSetRecordLock(dbCommon *precord)
|
||||
{
|
||||
lockRecord *plockRecord = precord->lset;
|
||||
lockSet *plockSet;
|
||||
STATUS status;
|
||||
semTakeStatus status;
|
||||
|
||||
/*Make sure that dbLockSetGblLock was called*/
|
||||
if(!changingLockSets) {
|
||||
epicsPrintf("dbLockSetRecordLock called before dbLockSetGblLock\n");
|
||||
taskSuspend(0);
|
||||
cantProceed("dbLockSetRecordLock called before dbLockSetGblLock\n");
|
||||
}
|
||||
/*Must make sure that no other task has lock*/
|
||||
/*Must make sure that no other thread has lock*/
|
||||
if(!plockRecord) return;
|
||||
plockSet = plockRecord->plockSet;
|
||||
if(!plockSet) return;
|
||||
if(plockSet->task_id==taskIdSelf()) return;
|
||||
if(plockSet->thread_id==threadGetIdSelf()) return;
|
||||
/*Wait for up to 1 minute*/
|
||||
status = semTake(plockRecord->plockSet->semId,sysClkRateGet()*60);
|
||||
if(status==OK) {
|
||||
plockSet->start_time = tickGet();
|
||||
plockSet->task_id = taskIdSelf();
|
||||
status = semMutexTakeTimeout(plockRecord->plockSet->lock,60.0);
|
||||
if(status==semTakeOK) {
|
||||
plockSet->start_time = clockGetCurrentTick();
|
||||
plockSet->thread_id = threadGetIdSelf();
|
||||
plockSet->precord = (void *)precord;
|
||||
/*give it back in case it will not be changed*/
|
||||
semGive(plockRecord->plockSet->semId);
|
||||
semMutexGive(plockRecord->plockSet->lock);
|
||||
return;
|
||||
}
|
||||
/*Should never reach this point*/
|
||||
epicsPrintf("dbLockSetRecordLock timeout caller 0x%x owner 0x%x",
|
||||
taskIdSelf(),plockSet->task_id);
|
||||
epicsPrintf(" record %s\n",precord->name);
|
||||
errlogPrintf("dbLockSetRecordLock timeout caller 0x%x owner 0x%x",
|
||||
threadGetIdSelf(),plockSet->thread_id);
|
||||
errlogPrintf(" record %s\n",precord->name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,25 +197,25 @@ void dbScanLock(dbCommon *precord)
|
||||
{
|
||||
lockRecord *plockRecord;
|
||||
lockSet *plockSet;
|
||||
STATUS status;
|
||||
semTakeStatus status;
|
||||
|
||||
if(!(plockRecord= precord->lset)) {
|
||||
epicsPrintf("dbScanLock plockRecord is NULL record %s\n",
|
||||
precord->name);
|
||||
taskSuspend(0);
|
||||
threadSuspend(threadGetIdSelf());
|
||||
}
|
||||
while(TRUE) {
|
||||
if(changingLockSets) {
|
||||
semTake(globalWaitSemid,WAIT_FOREVER);
|
||||
semBinaryTakeAssert(globalWait);
|
||||
continue;
|
||||
}
|
||||
status = semTake(plockRecord->plockSet->semId,WAIT_FOREVER);
|
||||
/*semTake fails if semDelete was called while active*/
|
||||
if(status==OK) break;
|
||||
status = semMutexTake(plockRecord->plockSet->lock);
|
||||
/*semMutexTake fails if semMutexDestroy was called while active*/
|
||||
if(status==semTakeOK) break;
|
||||
}
|
||||
plockSet = plockRecord->plockSet;
|
||||
plockSet->start_time = tickGet();
|
||||
plockSet->task_id = taskIdSelf();
|
||||
plockSet->start_time = clockGetCurrentTick();
|
||||
plockSet->thread_id = threadGetIdSelf();
|
||||
plockSet->precord = (void *)precord;
|
||||
return;
|
||||
}
|
||||
@@ -241,7 +228,7 @@ void dbScanUnlock(dbCommon *precord)
|
||||
epicsPrintf("dbScanUnlock plockRecord or plockRecord->plockSet NULL\n");
|
||||
return;
|
||||
}
|
||||
semGive(plockRecord->plockSet->semId);
|
||||
semMutexGive(plockRecord->plockSet->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,10 +334,7 @@ void dbLockSetMerge(dbCommon *pfirst,dbCommon *psecond)
|
||||
p2lockRecord = (lockRecord *)ellNext(&p2lockRecord->node);
|
||||
}
|
||||
ellConcat(&p1lockSet->recordList,&p2lockSet->recordList);
|
||||
if(semDelete(p2lockSet->semId)!=OK) {
|
||||
errMessage(0,"dbLockSetMerge calling semDelete");
|
||||
taskSuspend(0);
|
||||
}
|
||||
semMutexDestroy(p2lockSet->lock);
|
||||
ellDelete(&lockList,&p2lockSet->node);
|
||||
free((void *)p2lockSet);
|
||||
return;
|
||||
@@ -409,10 +393,7 @@ void dbLockSetSplit(dbCommon *psource)
|
||||
}
|
||||
if(!plockRecord->plockSet) allocLock(plockRecord);
|
||||
}
|
||||
if(semDelete(plockSet->semId)!=OK) {
|
||||
errMessage(0,"dbLockSetSplit calling semDelete");
|
||||
taskSuspend(0);
|
||||
}
|
||||
semMutexDestroy(plockSet->lock);
|
||||
ellDelete(&lockList,&plockSet->node);
|
||||
free((void *)plockSet);
|
||||
free((void *)paprecord);
|
||||
@@ -453,14 +434,14 @@ long dblsr(char *recordname,int level)
|
||||
|
||||
printf("Lock Set %lu %d members",
|
||||
plockSet->id,ellCount(&plockSet->recordList));
|
||||
if(semTake(plockSet->semId,NO_WAIT)==OK) {
|
||||
semGive(plockSet->semId);
|
||||
if(semMutexTakeNoWait(plockSet->lock)==semTakeOK) {
|
||||
semMutexGive(plockSet->lock);
|
||||
printf(" Not Locked\n");
|
||||
} else {
|
||||
lockSeconds = plockSet->start_time;
|
||||
lockSeconds = (tickGet() - lockSeconds) / sysClkRateGet();
|
||||
lockSeconds = (clockGetCurrentTick() - lockSeconds) / clockGetRate();
|
||||
printf(" Locked %f seconds", lockSeconds);
|
||||
printf(" task 0x%x",plockSet->task_id);
|
||||
printf(" thread %p",plockSet->thread_id);
|
||||
if(! plockSet->precord || !plockSet->precord->name)
|
||||
printf(" NULL record or record name\n");
|
||||
else
|
||||
|
||||
@@ -31,26 +31,22 @@
|
||||
* .01 03-30-95 mrk Extracted from dbLink.c
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <taskLib.h>
|
||||
#include <semLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "fast_lock.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "errMdef.h"
|
||||
#include "ellLib.h"
|
||||
#include "recGbl.h"
|
||||
#include "dbDefs.h"
|
||||
#include "osiSem.h"
|
||||
#include "errlog.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbScan.h"
|
||||
#include "dbCommon.h"
|
||||
#include "errMdef.h"
|
||||
#include "ellLib.h"
|
||||
#include "recGbl.h"
|
||||
|
||||
/*NODE structure attached to ppnn field of each record in list*/
|
||||
typedef struct pnWaitNode {
|
||||
@@ -223,7 +219,7 @@ static void notifyCallback(CALLBACK *pcallback)
|
||||
dbScanUnlock(precord);
|
||||
ppn->restart = FALSE;
|
||||
ppn->callbackState = callbackNotActive;
|
||||
semGive((SEM_ID)ppn->waitForCallback);
|
||||
semBinaryGive((semId)ppn->waitForCallback);
|
||||
return;
|
||||
}
|
||||
if(ppn->callbackState==callbackActive) {
|
||||
@@ -251,14 +247,14 @@ void dbNotifyCancel(PUTNOTIFY *ppn)
|
||||
dbScanLock(precord);
|
||||
notifyCancel(ppn);
|
||||
if(ppn->callbackState == callbackActive) {
|
||||
ppn->waitForCallback = (void *)semBCreate(SEM_Q_FIFO,SEM_FULL);
|
||||
ppn->waitForCallback = (void *)semBinaryCreate(semFull);
|
||||
ppn->callbackState = callbackCanceled;
|
||||
dbScanUnlock(precord);
|
||||
if(semTake((SEM_ID)ppn->waitForCallback,sysClkRateGet()*10)!=OK) {
|
||||
errMessage(0,"dbNotifyCancel had semTake timeout");
|
||||
if(semBinaryTakeTimeout((semId)ppn->waitForCallback,10.0)!=semTakeOK) {
|
||||
errlogPrintf("dbNotifyCancel had semTake timeout\n");
|
||||
ppn->callbackState = callbackNotActive;
|
||||
}
|
||||
semDelete((SEM_ID)ppn->waitForCallback);
|
||||
semBinaryDestroy((semId)ppn->waitForCallback);
|
||||
} else {
|
||||
dbScanUnlock(precord);
|
||||
}
|
||||
|
||||
187
src/db/dbScan.c
187
src/db/dbScan.c
@@ -42,47 +42,46 @@
|
||||
* .12 05-02-96 mrk Allow multiple priority event scan
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <semLib.h>
|
||||
#include <rngLib.h>
|
||||
#include <ellLib.h>
|
||||
#include <vxLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <intLib.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbScan.h"
|
||||
#include "taskwd.h"
|
||||
#include "callback.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "devSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "task_params.h"
|
||||
#include "fast_lock.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "osiSem.h"
|
||||
#include "osiInterrupt.h"
|
||||
#include "osiThread.h"
|
||||
#include "osiClock.h"
|
||||
#include "cantProceed.h"
|
||||
#include "osiRing.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbScan.h"
|
||||
#include "taskwd.h"
|
||||
#include "callback.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "devSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "dbStaticLib.h"
|
||||
|
||||
extern struct dbBase *pdbbase;
|
||||
|
||||
/* SCAN ONCE */
|
||||
int onceQueueSize = 1000;
|
||||
static SEM_ID onceSem;
|
||||
static RING_ID onceQ;
|
||||
static int onceTaskId;
|
||||
static semId onceSem;
|
||||
static ringId onceQ;
|
||||
static threadId onceTaskId;
|
||||
|
||||
/*all other scan types */
|
||||
typedef struct scan_list{
|
||||
FAST_LOCK lock;
|
||||
semId lock;
|
||||
ELLLIST list;
|
||||
short modified;/*has list been modified?*/
|
||||
long ticks; /*ticks per period for periodic*/
|
||||
@@ -117,12 +116,12 @@ static io_scan_list *iosl_head[NUM_CALLBACK_PRIORITIES]={NULL,NULL,NULL};
|
||||
/* PERIODIC SCANNER */
|
||||
static int nPeriodic=0;
|
||||
static scan_list **papPeriodic; /* pointer to array of pointers*/
|
||||
static int *periodicTaskId; /*array of integers after allocation*/
|
||||
static void **periodicTaskId; /*array of pointers after allocation*/
|
||||
|
||||
/* Private routines */
|
||||
static void onceTask(void);
|
||||
static void initOnce(void);
|
||||
static void periodicTask(scan_list *psl);
|
||||
static void periodicTask(void *arg);
|
||||
static void initPeriodic(void);
|
||||
static void spawnPeriodic(int ind);
|
||||
static void wdPeriodic(long ind);
|
||||
@@ -323,7 +322,7 @@ int scanppl(double rate) /*print periodic list*/
|
||||
psl = papPeriodic[i];
|
||||
if(psl==NULL) continue;
|
||||
period = psl->ticks;
|
||||
period /= vxTicksPerSecond;
|
||||
period /= clockGetRate();
|
||||
if(rate>0.0 && (fabs(rate - period) >.05)) continue;
|
||||
sprintf(message,"Scan Period= %f seconds ",period);
|
||||
printList(psl,message);
|
||||
@@ -422,7 +421,7 @@ void scanIoInit(IOSCANPVT *ppioscanpvt)
|
||||
callbackSetPriority(priority,&piosl->callback);
|
||||
callbackSetUser(piosl,&piosl->callback);
|
||||
ellInit(&piosl->scan_list.list);
|
||||
FASTLOCKINIT(&piosl->scan_list.lock);
|
||||
piosl->scan_list.lock = semMutexCreate();
|
||||
piosl->next=iosl_head[priority];
|
||||
iosl_head[priority]=piosl;
|
||||
}
|
||||
@@ -448,16 +447,16 @@ void scanOnce(void *precord)
|
||||
int lockKey;
|
||||
int nput;
|
||||
|
||||
lockKey = intLock();
|
||||
nput = rngBufPut(onceQ,(void *)&precord,sizeof(precord));
|
||||
intUnlock(lockKey);
|
||||
lockKey = interruptLock();
|
||||
nput = ringPut(onceQ,(char *)&precord,sizeof(precord));
|
||||
interruptUnlock(lockKey);
|
||||
if(nput!=sizeof(precord)) {
|
||||
if(newOverflow)errMessage(0,"rngBufPut overflow in scanOnce");
|
||||
newOverflow = FALSE;
|
||||
}else {
|
||||
newOverflow = TRUE;
|
||||
}
|
||||
semGive(onceSem);
|
||||
semBinaryGive(onceSem);
|
||||
}
|
||||
|
||||
static void onceTask(void)
|
||||
@@ -465,10 +464,12 @@ static void onceTask(void)
|
||||
void *precord=NULL;
|
||||
|
||||
while(TRUE) {
|
||||
if(semTake(onceSem,WAIT_FOREVER)!=OK)
|
||||
errMessage(0,"dbScan: semTake returned error in onceTask");
|
||||
while (rngNBytes(onceQ)>=sizeof(precord)){
|
||||
if(rngBufGet(onceQ,(void *)&precord,sizeof(precord))!=sizeof(precord))
|
||||
if(semBinaryTake(onceSem)!=semTakeOK)
|
||||
errlogPrintf("dbScan: semBinaryTake returned error in onceTask");
|
||||
while(TRUE) {
|
||||
int nbytes = ringGet(onceQ,(void *)&precord,sizeof(precord));
|
||||
if(nbytes==0) break;
|
||||
if(nbytes!=sizeof(precord))
|
||||
errMessage(0,"dbScan: rngBufGet returned error in onceTask");
|
||||
dbScanLock(precord);
|
||||
dbProcess(precord);
|
||||
@@ -485,32 +486,38 @@ int scanOnceSetQueueSize(int size)
|
||||
|
||||
static void initOnce(void)
|
||||
{
|
||||
if((onceQ = rngCreate(sizeof(void *) * onceQueueSize))==NULL){
|
||||
errMessage(0,"dbScan: initOnce failed");
|
||||
exit(1);
|
||||
if((onceQ = ringCreate(sizeof(void *) * onceQueueSize))==NULL){
|
||||
cantProceed("dbScan: initOnce failed");
|
||||
}
|
||||
if((onceSem=semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL)
|
||||
if((onceSem=semBinaryCreate(semEmpty))==0)
|
||||
errMessage(0,"semBcreate failed in initOnce");
|
||||
onceTaskId = taskSpawn(SCANONCE_NAME,SCANONCE_PRI,SCANONCE_OPT,
|
||||
SCANONCE_STACK,(FUNCPTR)onceTask,
|
||||
0,0,0,0,0,0,0,0,0,0);
|
||||
onceTaskId = threadCreate("scanOnce",threadPriorityScanHigh,
|
||||
threadGetStackSize(threadStackBig),
|
||||
(THREADFUNC)onceTask,0);
|
||||
taskwdInsert(onceTaskId,NULL,0L);
|
||||
}
|
||||
|
||||
static void periodicTask(scan_list *psl)
|
||||
static void periodicTask(void *arg)
|
||||
{
|
||||
scan_list *psl = (scan_list *)arg;
|
||||
|
||||
unsigned long start_time,end_time;
|
||||
long delay;
|
||||
unsigned long start_time,end_time,diff;
|
||||
double delay;
|
||||
|
||||
start_time = tickGet();
|
||||
start_time = clockGetCurrentTick();
|
||||
while(TRUE) {
|
||||
if(interruptAccept)scanList(psl);
|
||||
end_time = tickGet();
|
||||
delay = psl->ticks - (end_time - start_time);
|
||||
if(delay<=0) delay=1;
|
||||
taskDelay(delay);
|
||||
start_time = tickGet();
|
||||
end_time = clockGetCurrentTick();
|
||||
if(end_time>=start_time) {
|
||||
diff = end_time - start_time;
|
||||
} else {
|
||||
/*unsigned long overflow*/
|
||||
diff = (UINT_MAX - start_time) + end_time;
|
||||
}
|
||||
delay = psl->ticks - diff;
|
||||
delay = (delay<=0.0) ? .1 : delay/clockGetRate();
|
||||
threadSleep(delay);
|
||||
start_time = clockGetCurrentTick();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,28 +536,30 @@ static void initPeriodic()
|
||||
}
|
||||
nPeriodic = pmenu->nChoice - SCAN_1ST_PERIODIC;
|
||||
papPeriodic = dbCalloc(nPeriodic,sizeof(scan_list*));
|
||||
periodicTaskId = dbCalloc(nPeriodic,sizeof(int));
|
||||
periodicTaskId = dbCalloc(nPeriodic,sizeof(void *));
|
||||
for(i=0; i<nPeriodic; i++) {
|
||||
psl = dbCalloc(1,sizeof(scan_list));
|
||||
papPeriodic[i] = psl;
|
||||
FASTLOCKINIT(&psl->lock);
|
||||
psl->lock = semMutexCreate();
|
||||
ellInit(&psl->list);
|
||||
sscanf(pmenu->papChoiceValue[i+SCAN_1ST_PERIODIC],"%f",&temp);
|
||||
psl->ticks = temp * vxTicksPerSecond;
|
||||
psl->ticks = temp * clockGetRate();
|
||||
}
|
||||
}
|
||||
|
||||
static void spawnPeriodic(int ind)
|
||||
{
|
||||
scan_list *psl;
|
||||
char taskName[20];
|
||||
char taskName[20];
|
||||
|
||||
psl = papPeriodic[ind];
|
||||
sprintf(taskName,"scan%ld",psl->ticks);
|
||||
periodicTaskId[ind] = taskSpawn(taskName,PERIODSCAN_PRI-ind,
|
||||
PERIODSCAN_OPT,PERIODSCAN_STACK,
|
||||
(FUNCPTR )periodicTask,(int)psl,
|
||||
0,0,0,0,0,0,0,0,0);
|
||||
periodicTaskId[ind] = threadCreate(
|
||||
taskName,
|
||||
threadPriorityScanLow + ind,
|
||||
threadGetStackSize(threadStackBig),
|
||||
periodicTask,
|
||||
(void *)psl);
|
||||
taskwdInsert(periodicTaskId[ind],wdPeriodic,(void *)(long)ind);
|
||||
}
|
||||
|
||||
@@ -562,7 +571,7 @@ static void wdPeriodic(long ind)
|
||||
psl = papPeriodic[ind];
|
||||
taskwdRemove(periodicTaskId[ind]);
|
||||
/*Unlock so that task can be resumed*/
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
spawnPeriodic(ind);
|
||||
}
|
||||
|
||||
@@ -579,21 +588,21 @@ static void printList(scan_list *psl,char *message)
|
||||
{
|
||||
scan_element *pse;
|
||||
|
||||
FASTLOCK(&psl->lock);
|
||||
semMutexTakeAssert(psl->lock);
|
||||
pse = (scan_element *)ellFirst(&psl->list);
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
if(pse==NULL) return;
|
||||
printf("%s\n",message);
|
||||
while(pse!=NULL) {
|
||||
printf(" %-28s\n",pse->precord->name);
|
||||
FASTLOCK(&psl->lock);
|
||||
semMutexTakeAssert(psl->lock);
|
||||
if(pse->pscan_list != psl) {
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
printf("Returning because list changed while processing.");
|
||||
return;
|
||||
}
|
||||
pse = (scan_element *)ellNext((void *)pse);
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,19 +614,19 @@ static void scanList(scan_list *psl)
|
||||
scan_element *pse,*prev;
|
||||
scan_element *next=0;
|
||||
|
||||
FASTLOCK(&psl->lock);
|
||||
psl->modified = FALSE;
|
||||
pse = (scan_element *)ellFirst(&psl->list);
|
||||
prev = NULL;
|
||||
if(pse) next = (scan_element *)ellNext((void *)pse);
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexTakeAssert(psl->lock);
|
||||
psl->modified = FALSE;
|
||||
pse = (scan_element *)ellFirst(&psl->list);
|
||||
prev = NULL;
|
||||
if(pse) next = (scan_element *)ellNext((void *)pse);
|
||||
semMutexGive(psl->lock);
|
||||
while(pse) {
|
||||
struct dbCommon *precord = pse->precord;
|
||||
|
||||
dbScanLock(precord);
|
||||
dbProcess(precord);
|
||||
dbScanUnlock(precord);
|
||||
FASTLOCK(&psl->lock);
|
||||
semMutexTakeAssert(psl->lock);
|
||||
if(!psl->modified) {
|
||||
prev = pse;
|
||||
pse = (scan_element *)ellNext((void *)pse);
|
||||
@@ -644,10 +653,10 @@ static void scanList(scan_list *psl)
|
||||
psl->modified = FALSE;
|
||||
} else {
|
||||
/*Too many changes. Just wait till next period*/
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
return;
|
||||
}
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,7 +684,7 @@ static void addToList(struct dbCommon *precord,scan_list *psl)
|
||||
{
|
||||
scan_element *pse,*ptemp;
|
||||
|
||||
FASTLOCK(&psl->lock);
|
||||
semMutexTakeAssert(psl->lock);
|
||||
pse = precord->spvt;
|
||||
if(pse==NULL) {
|
||||
pse = dbCalloc(1,sizeof(scan_element));
|
||||
@@ -694,7 +703,7 @@ static void addToList(struct dbCommon *precord,scan_list *psl)
|
||||
}
|
||||
if(ptemp==NULL) ellAdd(&psl->list,(void *)pse);
|
||||
psl->modified = TRUE;
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -702,20 +711,20 @@ static void deleteFromList(struct dbCommon *precord,scan_list *psl)
|
||||
{
|
||||
scan_element *pse;
|
||||
|
||||
FASTLOCK(&psl->lock);
|
||||
semMutexTakeAssert(psl->lock);
|
||||
if(precord->spvt==NULL) {
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
return;
|
||||
}
|
||||
pse = precord->spvt;
|
||||
if(pse==NULL || pse->pscan_list!=psl) {
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
errMessage(-1,"deleteFromList failed");
|
||||
return;
|
||||
}
|
||||
pse->pscan_list = NULL;
|
||||
ellDelete(&psl->list,(void *)pse);
|
||||
psl->modified = TRUE;
|
||||
FASTUNLOCK(&psl->lock);
|
||||
semMutexGive(psl->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,19 +58,16 @@ long dbtpf(char *pname,char *pvalue); /*test put field*/
|
||||
long dbior(char *pdrvName,int type); /*I/O report */
|
||||
int dbhcr(char *filename); /*Hardware Configuration Report*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <timexLib.h>
|
||||
|
||||
/*for open and close*/
|
||||
#include <ioLib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "ellLib.h"
|
||||
#include "fast_lock.h"
|
||||
#include "osiSem.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbCommon.h"
|
||||
@@ -443,7 +440,8 @@ long dbtr(char *pname)
|
||||
printf("record active\n");
|
||||
return(1);
|
||||
}
|
||||
if(FASTLOCKTEST(&precord->mlok)) {
|
||||
if(semMutexTakeNoWait(precord->mlok)==semTakeOK) {
|
||||
semBinaryGive(precord->mlok);
|
||||
printf("record locked\n");
|
||||
return(1);
|
||||
}
|
||||
@@ -1294,53 +1292,3 @@ static void dbpr_msg_flush(TAB_BUFFER *pMsgBuff,int tab_size)
|
||||
pMsgBuff->pNexTab = pMsgBuff->out_buff + tab_size;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call dbProcess() 100 times to make
|
||||
* sure Measurement is accurate, since
|
||||
* timexN() makes use of the 60Hz clock
|
||||
*/
|
||||
static void timing_routine(precord)
|
||||
struct dbCommon *precord;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <100; i++) {
|
||||
dbProcess(precord);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Time execution of record "record_name"
|
||||
*/
|
||||
long dbt(record_name)
|
||||
char *record_name;
|
||||
{
|
||||
DBADDR address;
|
||||
struct dbCommon *precord;
|
||||
long status = 0;
|
||||
|
||||
/*
|
||||
* Convert Name To Address
|
||||
*/
|
||||
status = dbNameToAddr(record_name, &address);
|
||||
|
||||
if (status != 0) {
|
||||
errMessage(status," dbNameToAddr failed");
|
||||
return(status);
|
||||
}
|
||||
|
||||
precord = address.precord;
|
||||
|
||||
printf("!! Time for 100 executions of %s: !!\n", record_name);
|
||||
|
||||
/*
|
||||
* Time the record
|
||||
*/
|
||||
dbScanLock(precord);
|
||||
timexN((FUNCPTR)timing_routine, (int)precord,
|
||||
0,0,0,0,0,0,0);
|
||||
dbScanUnlock(precord);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -45,11 +45,9 @@
|
||||
*** the presumed order in dbAccess.c's dbGetField() routine
|
||||
***/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <fioLib.h>
|
||||
#include <string.h>
|
||||
#include <types.h>
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* .04 02-02-94 mrk added tpn (test put notify)
|
||||
* .05 02-03-94 mrk gft was overrunning its buffer for arrays
|
||||
*/
|
||||
#include <vxWorks.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -655,11 +655,14 @@ static void tpnCallback(PUTNOTIFY *ppn)
|
||||
{
|
||||
struct dbAddr *pdbaddr = (struct dbAddr *)ppn->paddr;
|
||||
long status = ppn->status;
|
||||
char *pname;
|
||||
|
||||
/*This is really cheating. It only works because first field is name*/
|
||||
pname = (char *)pdbaddr->precord;
|
||||
if(status==0)
|
||||
printf("tpnCallback: success record=%s\n",ppn->paddr->precord);
|
||||
printf("tpnCallback: success record=%s\n",pname);
|
||||
else
|
||||
recGblRecordError(status,pdbaddr->precord,"tpnCallback");
|
||||
recGblRecordError(status,pname,"tpnCallback");
|
||||
free((void *)pdbaddr);
|
||||
free(ppn);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,10 @@ of this distribution.
|
||||
* .01 10APR96 mrk list db to CA links
|
||||
****************************************************************/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include "dbStaticLib.h"
|
||||
#include "link.h"
|
||||
|
||||
1103
src/db/devLib.c
1103
src/db/devLib.c
File diff suppressed because it is too large
Load Diff
444
src/db/devLib.h
444
src/db/devLib.h
@@ -1,444 +0,0 @@
|
||||
/* devLib.h */
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Original Author: Marty Kraimer
|
||||
* Author: Jeff Hill
|
||||
* Date: 03-10-93
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 03-10-93 joh original
|
||||
* .02 03-18-93 joh added fundamental address type mapping
|
||||
* .03 03-23-93 joh changed input parameter to be a fund
|
||||
* address type in favor of the argument
|
||||
* that the BSP will be reconfigured
|
||||
* to use an EPICS standard address
|
||||
* mode
|
||||
* .04 05-06-93 joh added new parameter to devDisconnectInterrupt().
|
||||
* See comment below.
|
||||
* .05 05-28-93 joh Added an argument to devRegisterAddress()
|
||||
* .06 05-28-93 joh Added devAddressMap()
|
||||
* .07 06-14-93 joh Added devAllocAddress()
|
||||
*
|
||||
* Notes:
|
||||
* ------
|
||||
* .01 03-23-93 joh We will only have problems with mod .03
|
||||
* above if the CPU maintains the different
|
||||
* address modes in different address spaces
|
||||
* and we have a card or a user that insists
|
||||
* on not using the default address type
|
||||
* .02 06-14-93 joh needs devAllocInterruptVector() routine
|
||||
*/
|
||||
|
||||
#ifndef INCdevLibh
|
||||
#define INCdevLibh 1
|
||||
|
||||
#include <dbDefs.h>
|
||||
|
||||
/*
|
||||
* epdevAddressType & EPICStovxWorksAddrType
|
||||
* devLib.c must change in unison
|
||||
*/
|
||||
typedef enum {
|
||||
atVMEA16,
|
||||
atVMEA24,
|
||||
atVMEA32,
|
||||
atISA, /* memory mapped ISA access (until now only on PC) */
|
||||
atLast /* atLast must be the last enum in this list */
|
||||
} epicsAddressType;
|
||||
|
||||
/*
|
||||
* pointer to an array of strings for each of
|
||||
* the above address types
|
||||
*/
|
||||
extern const char *epicsAddressTypeName[];
|
||||
|
||||
long devAddressMap(void); /* print an address map */
|
||||
|
||||
/*
|
||||
* devReadProbe()
|
||||
*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long devReadProbe (unsigned wordSize, volatile const void *ptr, void *pValueRead);
|
||||
|
||||
/*
|
||||
* devNoResponseProbe()
|
||||
*
|
||||
* Verifies that no devices respond at naturally aligned words
|
||||
* within the specified address range. Return success if no devices
|
||||
* respond. Returns an error if a device does respond or if
|
||||
* a physical address for a naturally aligned word cant be mapped.
|
||||
* Checks all naturally aligned word sizes between char and long for
|
||||
* the entire specified range of bytes.
|
||||
*/
|
||||
long devNoResponseProbe(
|
||||
epicsAddressType addrType,
|
||||
size_t base,
|
||||
size_t size
|
||||
);
|
||||
|
||||
/*
|
||||
* devWriteProbe
|
||||
*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long devWriteProbe (unsigned wordSize, volatile void *ptr, const void *pValueWritten);
|
||||
|
||||
long devRegisterAddress(
|
||||
const char *pOwnerName,
|
||||
epicsAddressType addrType,
|
||||
size_t logicalBaseAddress,
|
||||
size_t size, /* bytes */
|
||||
volatile void **pPhysicalAddress);
|
||||
|
||||
long devUnregisterAddress(
|
||||
epicsAddressType addrType,
|
||||
size_t logicalBaseAddress,
|
||||
const char *pOwnerName);
|
||||
|
||||
/*
|
||||
* allocate and register an unoccupied address block
|
||||
*/
|
||||
long devAllocAddress(
|
||||
const char *pOwnerName,
|
||||
epicsAddressType addrType,
|
||||
size_t size,
|
||||
unsigned alignment, /*n ls bits zero in addr*/
|
||||
volatile void **pLocalAddress);
|
||||
|
||||
/*
|
||||
* connect ISR to a VME interrupt vector
|
||||
*/
|
||||
long devConnectInterruptVME(
|
||||
unsigned vectorNumber,
|
||||
void (*pFunction)(void *),
|
||||
void *parameter);
|
||||
|
||||
/*
|
||||
* connect ISR to an ISA interrupt level
|
||||
* (not implemented)
|
||||
* (API should be reviewed)
|
||||
*/
|
||||
long devConnectInterruptISA(
|
||||
unsigned interruptLevel,
|
||||
void (*pFunction)(void *),
|
||||
void *parameter);
|
||||
|
||||
/*
|
||||
* connect ISR to a PCI interrupt
|
||||
* (not implemented)
|
||||
* (API should be reviewed)
|
||||
*/
|
||||
long devConnectInterruptPCI(
|
||||
unsigned bus,
|
||||
unsigned device,
|
||||
unsigned function,
|
||||
void (*pFunction)(void *),
|
||||
void *parameter);
|
||||
|
||||
/*
|
||||
* disconnect ISR from a VME interrupt vector
|
||||
*
|
||||
* The parameter pFunction should be set to the C function pointer that
|
||||
* was connected. It is used as a key to prevent a driver from inadvertently
|
||||
* removing an interrupt handler that it didn't install
|
||||
*/
|
||||
long devDisconnectInterruptVME(
|
||||
unsigned vectorNumber,
|
||||
void (*pFunction)(void *));
|
||||
|
||||
/*
|
||||
* disconnect ISR from an ISA interrupt level
|
||||
* (not implemented)
|
||||
* (API should be reviewed)
|
||||
*
|
||||
* The parameter pFunction should be set to the C function pointer that
|
||||
* was connected. It is used as a key to prevent a driver from inadvertently
|
||||
* removing an interrupt handler that it didn't install
|
||||
*/
|
||||
long devDisconnectInterruptISA(
|
||||
unsigned interruptLevel,
|
||||
void (*pFunction)(void *));
|
||||
|
||||
/*
|
||||
* disconnect ISR from a PCI interrupt
|
||||
* (not implemented)
|
||||
* (API should be reviewed)
|
||||
*
|
||||
* The parameter pFunction should be set to the C function pointer that
|
||||
* was connected. It is used as a key to prevent a driver from inadvertently
|
||||
* removing an interrupt handler that it didn't install
|
||||
*/
|
||||
long devDisconnectInterruptPCI(
|
||||
unsigned bus,
|
||||
unsigned device,
|
||||
unsigned function,
|
||||
void (*pFunction)(void *));
|
||||
|
||||
/*
|
||||
* determine if a VME interrupt vector is in use
|
||||
*
|
||||
* returns boolean
|
||||
*/
|
||||
int devInterruptInUseVME (unsigned vectorNumber);
|
||||
|
||||
/*
|
||||
* determine if an ISA interrupt level is in use
|
||||
* (not implemented)
|
||||
*
|
||||
* returns boolean
|
||||
*/
|
||||
int devInterruptLevelInUseISA (unsigned interruptLevel);
|
||||
|
||||
/*
|
||||
* determine if a PCI interrupt is in use
|
||||
* (not implemented)
|
||||
*
|
||||
* returns boolean
|
||||
*/
|
||||
int devInterruptInUsePCI (unsigned bus, unsigned device,
|
||||
unsigned function);
|
||||
|
||||
typedef enum {intVME, intVXI, intISA} epicsInterruptType;
|
||||
|
||||
/*
|
||||
* enable VME interrupt level
|
||||
*/
|
||||
long devEnableInterruptLevelVME (unsigned level);
|
||||
|
||||
/*
|
||||
* enable ISA interrupt level
|
||||
*/
|
||||
long devEnableInterruptLevelISA (unsigned level);
|
||||
|
||||
/*
|
||||
* not implemented - API needs to be reviewed
|
||||
*/
|
||||
long devEnableInterruptLevelPCI (unsigned level,
|
||||
unsigned bus, unsigned device, unsigned function);
|
||||
|
||||
/*
|
||||
* disable VME interrupt level
|
||||
*/
|
||||
long devDisableInterruptLevelVME (unsigned level);
|
||||
|
||||
/*
|
||||
* disable ISA interrupt level
|
||||
*/
|
||||
long devDisableInterruptLevelISA (unsigned level);
|
||||
|
||||
/*
|
||||
* not implemented - API needs to be reviewed
|
||||
*/
|
||||
long devDisableInterruptLevelPCI (unsigned level,
|
||||
unsigned bus, unsigned device, unsigned function);
|
||||
|
||||
/*
|
||||
* Routines to allocate and free memory in the A24 memory region.
|
||||
*
|
||||
*/
|
||||
void *devLibA24Malloc(size_t);
|
||||
void *devLibA24Calloc(size_t);
|
||||
void devLibA24Free(void *pBlock);
|
||||
|
||||
/*
|
||||
* Normalize a digital value and convert it to type TYPE
|
||||
*
|
||||
* Ex:
|
||||
* float f;
|
||||
* int d;
|
||||
* f = devNormalizeDigital(d,12)
|
||||
*
|
||||
*/
|
||||
#define devCreateMask(NBITS) ((1<<(NBITS))-1)
|
||||
#define devDigToNml(DIGITAL,NBITS) \
|
||||
(((double)(DIGITAL))/devCreateMask(NBITS))
|
||||
#define devNmlToDig(NORMAL,NBITS) \
|
||||
(((long)(NORMAL)) * devCreateMask(NBITS))
|
||||
|
||||
/*
|
||||
*
|
||||
* Alignment mask
|
||||
* (for use when testing to see if the proper number of least
|
||||
* significant bits are zero)
|
||||
*
|
||||
*/
|
||||
#define devCreateAlignmentMask(CTYPE)\
|
||||
(sizeof(CTYPE)>sizeof(double)?sizeof(double)-1:sizeof(CTYPE)-1)
|
||||
|
||||
/*
|
||||
* pointer aligned test
|
||||
* (returns true if the pointer is on the worst case alignemnt
|
||||
* boundary for its type)
|
||||
*/
|
||||
#define devPtrAlignTest(PTR) (!(devCreateAlignmentMask(*PTR)&(long)(PTR)))
|
||||
|
||||
/*
|
||||
* virtual OS layer for devLib.c
|
||||
*/
|
||||
struct devLibVirtualOS {
|
||||
/*
|
||||
* maps logical address to physical address, but does not detect
|
||||
* two device drivers that are using the same address range
|
||||
*/
|
||||
long (*pDevMapAddr) (epicsAddressType addrType, unsigned options,
|
||||
size_t logicalAddress, size_t size, volatile void **ppPhysicalAddress);
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long (*pDevReadProbe) (unsigned wordSize, volatile const void *ptr, void *pValueRead);
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long (*pDevWriteProbe) (unsigned wordSize, volatile void *ptr, const void *pValueWritten);
|
||||
|
||||
/*
|
||||
* connect ISR to a VME interrupt vector
|
||||
* (required for backwards compatibility)
|
||||
*/
|
||||
long (*pDevConnectInterruptVME) (unsigned vectorNumber,
|
||||
void (*pFunction)(), void *parameter);
|
||||
|
||||
/*
|
||||
* disconnect ISR from a VME interrupt vector
|
||||
* (required for backwards compatibility)
|
||||
*/
|
||||
long (*pDevDisconnectInterruptVME) (unsigned vectorNumber,
|
||||
void (*pFunction)(void *));
|
||||
|
||||
/*
|
||||
* enable VME interrupt level
|
||||
*/
|
||||
long (*pDevEnableInterruptLevelVME) (unsigned level);
|
||||
|
||||
/*
|
||||
* disable VME interrupt level
|
||||
*/
|
||||
long (*pDevDisableInterruptLevelVME) (unsigned level);
|
||||
};
|
||||
|
||||
/*
|
||||
* error codes (and messages) associated with devLib.c
|
||||
*/
|
||||
#define S_dev_success 0
|
||||
#define S_dev_vectorInUse (M_devLib| 1) /*interrupt vector in use*/
|
||||
#define S_dev_vecInstlFail (M_devLib| 2) /*interrupt vector install failed*/
|
||||
#define S_dev_uknIntType (M_devLib| 3) /*Unrecognized interrupt type*/
|
||||
#define S_dev_vectorNotInUse (M_devLib| 4) /*Interrupt vector not in use by caller*/
|
||||
#define S_dev_badA16 (M_devLib| 5) /*Invalid VME A16 address*/
|
||||
#define S_dev_badA24 (M_devLib| 6) /*Invalid VME A24 address*/
|
||||
#define S_dev_badA32 (M_devLib| 7) /*Invalid VME A32 address*/
|
||||
#define S_dev_uknAddrType (M_devLib| 8) /*Unrecognized address space type*/
|
||||
#define S_dev_addressOverlap (M_devLib| 9) /*Specified device address overlaps another device*/
|
||||
#define S_dev_identifyOverlap (M_devLib| 10) /*This device already owns the address range*/
|
||||
#define S_dev_addrMapFail (M_devLib| 11) /*unable to map address*/
|
||||
#define S_dev_intDisconnect (M_devLib| 12) /*Interrupt at vector disconnected from an EPICS device*/
|
||||
#define S_dev_internal (M_devLib| 13) /*Internal failure*/
|
||||
#define S_dev_intEnFail (M_devLib| 14) /*unable to enable interrupt level*/
|
||||
#define S_dev_intDissFail (M_devLib| 15) /*unable to disable interrupt level*/
|
||||
#define S_dev_noMemory (M_devLib| 16) /*Memory allocation failed*/
|
||||
#define S_dev_addressNotFound (M_devLib| 17) /*Specified device address unregistered*/
|
||||
#define S_dev_noDevice (M_devLib| 18) /*No device at specified address*/
|
||||
#define S_dev_wrongDevice (M_devLib| 19) /*Wrong device type found at specified address*/
|
||||
#define S_dev_badSignalNumber (M_devLib| 20) /*Signal number (offset) to large*/
|
||||
#define S_dev_badSignalCount (M_devLib| 21) /*Signal count to large*/
|
||||
#define S_dev_badRequest (M_devLib| 22) /*Device does not support requested operation*/
|
||||
#define S_dev_highValue (M_devLib| 23) /*Parameter to high*/
|
||||
#define S_dev_lowValue (M_devLib| 24) /*Parameter to low*/
|
||||
#define S_dev_multDevice (M_devLib| 25) /*Specified address is ambiguous (more than one device responds)*/
|
||||
#define S_dev_badSelfTest (M_devLib| 26) /*Device self test failed*/
|
||||
#define S_dev_badInit (M_devLib| 27) /*Device failed during initialization*/
|
||||
#define S_dev_hdwLimit (M_devLib| 28) /*Input exceeds Hardware Limit*/
|
||||
#define S_dev_deviceDoesNotFit (M_devLib| 29) /*Unable to locate address space for device*/
|
||||
#define S_dev_deviceTMO (M_devLib| 30) /*device timed out*/
|
||||
#define S_dev_badFunction (M_devLib| 31) /*bad function pointer*/
|
||||
#define S_dev_badVector (M_devLib| 32) /*bad interrupt vector*/
|
||||
#define S_dev_badArgument (M_devLib| 33) /*bad function argument*/
|
||||
#define S_dev_vxWorksIntEnFail S_dev_intEnFail
|
||||
|
||||
/*
|
||||
* NOTE: this routine has been deprecated. It exists
|
||||
* for backwards compatibility purposes only.
|
||||
*
|
||||
* Please use one of devConnectInterruptVME, devConnectInterruptPCI,
|
||||
* devConnectInterruptISA etc. devConnectInterrupt will be removed
|
||||
* in a future release.
|
||||
*/
|
||||
long devConnectInterrupt(
|
||||
epicsInterruptType intType,
|
||||
unsigned vectorNumber,
|
||||
void (*pFunction)(),
|
||||
void *parameter);
|
||||
|
||||
/*
|
||||
* NOTE: this routine has been deprecated. It exists
|
||||
* for backwards compatibility purposes only.
|
||||
*
|
||||
* Please use one of devDisconnectInterruptVME, devDisconnectInterruptPCI,
|
||||
* devDisconnectInterruptISA etc. devDisconnectInterrupt will be removed
|
||||
* in a future release.
|
||||
*/
|
||||
long devDisconnectInterrupt(
|
||||
epicsInterruptType intType,
|
||||
unsigned vectorNumber,
|
||||
void (*pFunction)());
|
||||
|
||||
/*
|
||||
* NOTE: this routine has been deprecated. It exists
|
||||
* for backwards compatibility purposes only.
|
||||
*
|
||||
* Please use one of devEnableInterruptLevelVME, devEnableInterruptLevelPCI,
|
||||
* devEnableInterruptLevelISA etc. devEnableInterruptLevel will be removed
|
||||
* in a future release.
|
||||
*/
|
||||
long devEnableInterruptLevel(epicsInterruptType intType, unsigned level);
|
||||
|
||||
/*
|
||||
* NOTE: this routine has been deprecated. It exists
|
||||
* for backwards compatibility purposes only.
|
||||
*
|
||||
* Please use one of devDisableInterruptLevelVME, devDisableInterruptLevelISA,
|
||||
* devDisableInterruptLevelPCI etc. devDisableInterruptLevel will be removed
|
||||
* in a future release.
|
||||
*/
|
||||
long devDisableInterruptLevel (epicsInterruptType intType, unsigned level);
|
||||
|
||||
/*
|
||||
* NOTE: this routine has been deprecated. It exists
|
||||
* for backwards compatibility purposes only.
|
||||
*
|
||||
* Please use devNoResponseProbe(). locationProbe() will be removed
|
||||
* in a future release.
|
||||
*/
|
||||
long locationProbe (epicsAddressType addrType, char *pLocation);
|
||||
|
||||
#endif /* devLib.h*/
|
||||
@@ -1,430 +0,0 @@
|
||||
/*
|
||||
* devLibVxWorks.c
|
||||
* @(#)$Id$
|
||||
*
|
||||
* Archictecture dependent support for common device driver resources
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 10-30-98
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*/
|
||||
|
||||
static char *sccsID = "@(#) $Id$";
|
||||
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <types.h>
|
||||
#include <iv.h>
|
||||
#include <vme.h>
|
||||
#include <sysLib.h>
|
||||
#include <memLib.h>
|
||||
#include <intLib.h>
|
||||
#include <logLib.h>
|
||||
#include <vxLib.h>
|
||||
|
||||
#include "devLib.h"
|
||||
#include "epicsDynLink.h"
|
||||
|
||||
/*
|
||||
* A list of the names of the unexpected interrupt handlers
|
||||
* ( some of these are provided by wrs )
|
||||
*/
|
||||
LOCAL char *defaultHandlerNames[] = {
|
||||
"_excStub",
|
||||
"_excIntStub",
|
||||
"_unsolicitedHandlerEPICS"};
|
||||
|
||||
typedef void myISR (void *pParam);
|
||||
LOCAL myISR *defaultHandlerAddr[NELEMENTS(defaultHandlerNames)];
|
||||
|
||||
LOCAL myISR *isrFetch(unsigned vectorNumber);
|
||||
|
||||
/*
|
||||
* this routine needs to be in the symbol table
|
||||
* for this code to work correctly
|
||||
*/
|
||||
void unsolicitedHandlerEPICS(int vectorNumber);
|
||||
|
||||
/*
|
||||
* this is in veclist.c
|
||||
*/
|
||||
int cISRTest(void (*)(), void (**)(), void **);
|
||||
|
||||
/*
|
||||
* we use a translation between an EPICS encoding
|
||||
* and a vxWorks encoding here
|
||||
* to reduce dependency of drivers on vxWorks
|
||||
*
|
||||
* we assume that the BSP are configured to use these
|
||||
* address modes by default
|
||||
*/
|
||||
#define EPICSAddrTypeNoConvert -1
|
||||
int EPICStovxWorksAddrType[]
|
||||
= {
|
||||
VME_AM_SUP_SHORT_IO,
|
||||
VME_AM_STD_SUP_DATA,
|
||||
VME_AM_EXT_SUP_DATA,
|
||||
EPICSAddrTypeNoConvert
|
||||
};
|
||||
|
||||
LOCAL void initHandlerAddrList(void);
|
||||
|
||||
/*
|
||||
* maps logical address to physical address, but does not detect
|
||||
* two device drivers that are using the same address range
|
||||
*/
|
||||
LOCAL long vxDevMapAddr (epicsAddressType addrType, unsigned options,
|
||||
size_t logicalAddress, size_t size, volatile void **ppPhysicalAddress);
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long vxDevReadProbe (unsigned wordSize, volatile const void *ptr, void *pValue);
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long vxDevWriteProbe (unsigned wordSize, volatile void *ptr, const void *pValue);
|
||||
|
||||
/*
|
||||
* used by dynamic bind in devLib.c
|
||||
*/
|
||||
const struct devLibVirtualOS devLibVirtualOS =
|
||||
{vxDevMapAddr, vxDevReadProbe, vxDevWriteProbe,
|
||||
devConnectInterruptVME, devDisconnectInterruptVME,
|
||||
devEnableInterruptLevelVME, devDisableInterruptLevelVME};
|
||||
|
||||
#define SUCCESS 0
|
||||
|
||||
/*
|
||||
* devConnectInterruptVME
|
||||
*
|
||||
* wrapper to minimize driver dependency on vxWorks
|
||||
*/
|
||||
long devConnectInterruptVME (
|
||||
unsigned vectorNumber,
|
||||
void (*pFunction)(),
|
||||
void *parameter)
|
||||
{
|
||||
int status;
|
||||
|
||||
|
||||
if (devInterruptInUseVME(vectorNumber)) {
|
||||
return S_dev_vectorInUse;
|
||||
}
|
||||
status = intConnect(
|
||||
(void *)INUM_TO_IVEC(vectorNumber),
|
||||
pFunction,
|
||||
(int) parameter);
|
||||
if (status<0) {
|
||||
return S_dev_vecInstlFail;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* devDisconnectInterruptVME()
|
||||
*
|
||||
* wrapper to minimize driver dependency on vxWorks
|
||||
*
|
||||
* The parameter pFunction should be set to the C function pointer that
|
||||
* was connected. It is used as a key to prevent a driver from removing
|
||||
* an interrupt handler that was installed by another driver
|
||||
*
|
||||
*/
|
||||
long devDisconnectInterruptVME (
|
||||
unsigned vectorNumber,
|
||||
void (*pFunction)()
|
||||
)
|
||||
{
|
||||
void (*psub)();
|
||||
int status;
|
||||
|
||||
/*
|
||||
* If pFunction not connected to this vector
|
||||
* then they are probably disconnecting from the wrong vector
|
||||
*/
|
||||
psub = isrFetch(vectorNumber);
|
||||
if(psub != pFunction){
|
||||
return S_dev_vectorNotInUse;
|
||||
}
|
||||
|
||||
status = intConnect(
|
||||
(void *)INUM_TO_IVEC(vectorNumber),
|
||||
unsolicitedHandlerEPICS,
|
||||
(int) vectorNumber);
|
||||
if(status<0){
|
||||
return S_dev_vecInstlFail;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* enable VME interrupt level
|
||||
*/
|
||||
long devEnableInterruptLevelVME (unsigned level)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = sysIntEnable (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* enable ISA interrupt level
|
||||
*/
|
||||
long devEnableInterruptLevelISA (unsigned level)
|
||||
{
|
||||
# if CPU == I80386
|
||||
int s;
|
||||
s = sysIntEnablePIC (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
return SUCCESS;
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
}
|
||||
|
||||
/*
|
||||
* disable ISA interrupt level
|
||||
*/
|
||||
long devDisableInterruptLevelISA (unsigned level)
|
||||
{
|
||||
# if CPU == I80386
|
||||
int s;
|
||||
s = sysIntDisablePIC (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intEnFail;
|
||||
}
|
||||
# else
|
||||
return S_dev_intEnFail;
|
||||
# endif
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* disable VME interrupt level
|
||||
*/
|
||||
long devDisableInterruptLevelVME (unsigned level)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = sysIntDisable (level);
|
||||
if (s!=OK) {
|
||||
return S_dev_intDissFail;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* vxDevMapAddr ()
|
||||
*/
|
||||
LOCAL long vxDevMapAddr (epicsAddressType addrType, unsigned options,
|
||||
size_t logicalAddress, size_t size, volatile void **ppPhysicalAddress)
|
||||
{
|
||||
long status;
|
||||
|
||||
if (ppPhysicalAddress==NULL) {
|
||||
return S_dev_badArgument;
|
||||
}
|
||||
|
||||
if (EPICStovxWorksAddrType[addrType] == EPICSAddrTypeNoConvert)
|
||||
{
|
||||
*ppPhysicalAddress = (void *) logicalAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = sysBusToLocalAdrs (EPICStovxWorksAddrType[addrType],
|
||||
(char *) logicalAddress, (char **)ppPhysicalAddress);
|
||||
if (status) {
|
||||
return S_dev_addrMapFail;
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" read at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long vxDevReadProbe (unsigned wordSize, volatile const void *ptr, void *pValue)
|
||||
{
|
||||
long status;
|
||||
|
||||
/*
|
||||
* this global variable exists in the nivxi library
|
||||
*/
|
||||
status = vxMemProbe ((char *)ptr, VX_READ, wordSize, (char *) pValue);
|
||||
if (status!=OK) {
|
||||
return S_dev_noDevice;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* a bus error safe "wordSize" write at the specified address which returns
|
||||
* unsuccessful status if the device isnt present
|
||||
*/
|
||||
long vxDevWriteProbe (unsigned wordSize, volatile void *ptr, const void *pValue)
|
||||
{
|
||||
long status;
|
||||
|
||||
/*
|
||||
* this global variable exists in the nivxi library
|
||||
*/
|
||||
status = vxMemProbe ((char *)ptr, VX_READ, wordSize, (char *) pValue);
|
||||
if (status!=OK) {
|
||||
return S_dev_noDevice;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* isrFetch()
|
||||
*/
|
||||
LOCAL myISR *isrFetch(unsigned vectorNumber)
|
||||
{
|
||||
myISR *psub;
|
||||
myISR *pCISR;
|
||||
void *pParam;
|
||||
int s;
|
||||
|
||||
/*
|
||||
* fetch the handler or C stub attached at this vector
|
||||
*/
|
||||
psub = (myISR *) intVecGet((FUNCPTR *)INUM_TO_IVEC(vectorNumber));
|
||||
|
||||
/*
|
||||
* from libvxWorks/veclist.c
|
||||
*
|
||||
* checks to see if it is a C ISR
|
||||
* and if so finds the function pointer and
|
||||
* the parameter passed
|
||||
*/
|
||||
s = cISRTest(psub, &pCISR, &pParam);
|
||||
if(!s){
|
||||
psub = pCISR;
|
||||
}
|
||||
|
||||
return psub;
|
||||
}
|
||||
|
||||
/*
|
||||
* determine if a VME interrupt vector is in use
|
||||
*/
|
||||
int devInterruptInUseVME (unsigned vectorNumber)
|
||||
{
|
||||
static int init;
|
||||
int i;
|
||||
myISR *psub;
|
||||
|
||||
if (!init) {
|
||||
initHandlerAddrList();
|
||||
init = TRUE;
|
||||
}
|
||||
|
||||
psub = isrFetch (vectorNumber);
|
||||
|
||||
/*
|
||||
* its a C routine. Does it match a default handler?
|
||||
*/
|
||||
for (i=0; i<NELEMENTS(defaultHandlerAddr); i++) {
|
||||
if (defaultHandlerAddr[i] == psub) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* unsolicitedHandlerEPICS()
|
||||
* what gets called if they disconnect from an
|
||||
* interrupt and an interrupt arrives on the
|
||||
* disconnected vector
|
||||
*
|
||||
*/
|
||||
void unsolicitedHandlerEPICS(int vectorNumber)
|
||||
{
|
||||
/*
|
||||
* call logMsg() and not errMessage()
|
||||
* so we are certain that printf()
|
||||
* does not get called at interrupt level
|
||||
*/
|
||||
logMsg(
|
||||
"%s: line=%d: Interrupt to EPICS disconnected vector = 0X %X",
|
||||
(int)__FILE__,
|
||||
__LINE__,
|
||||
vectorNumber,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* initHandlerAddrList()
|
||||
* init list of interrupt handlers to ignore
|
||||
*
|
||||
*/
|
||||
LOCAL
|
||||
void initHandlerAddrList(void)
|
||||
{
|
||||
int i;
|
||||
SYM_TYPE type;
|
||||
int status;
|
||||
|
||||
for (i=0; i<NELEMENTS(defaultHandlerNames); i++) {
|
||||
status = symFindByNameEPICS (sysSymTbl,
|
||||
defaultHandlerNames[i],
|
||||
(char **)&defaultHandlerAddr[i],
|
||||
&type);
|
||||
if (status != OK) {
|
||||
errPrintf(
|
||||
S_dev_internal,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"initHandlerAddrList() %s not in sym table",
|
||||
defaultHandlerNames[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1979
src/db/drvTS.c
1979
src/db/drvTS.c
File diff suppressed because it is too large
Load Diff
252
src/db/drvTS.h
252
src/db/drvTS.h
@@ -1,252 +0,0 @@
|
||||
#ifndef __DRVTS_h__
|
||||
#define __DRVTS_h__
|
||||
|
||||
/*
|
||||
* $Log$
|
||||
* Revision 1.2 1998/03/19 20:41:16 mrk
|
||||
* Checked for Y2K complience. It turns out it was even ok when NTP time overflows
|
||||
* in 2036. However it was modified so that no overflows should occur while convert
|
||||
* ing between NTP, UNIX, and EPICS epochs.
|
||||
* In addition the conversion of fractions of a second to nanaoseconds was changed
|
||||
* Formatting was changed so that interesting code does not run off right side of page.
|
||||
* Hopefully EPICS base is now fine for Y2K.
|
||||
* In fact it should be fine (as far as time is converned) until the Unix epoch
|
||||
* overflows a 32 unsigned integer in the year 2106.
|
||||
*
|
||||
* Revision 1.1 1996/01/25 21:11:56 mrk
|
||||
* moved includes; .ascii=> .db; path changes
|
||||
*
|
||||
* Revision 1.12 1995/08/30 15:39:07 jbk
|
||||
* Added global variables for force accurate time stamps and direct time.
|
||||
*
|
||||
* Revision 1.11 1995/08/18 13:18:13 mrk
|
||||
* Added function prototypes for ansi c
|
||||
*
|
||||
* Revision 1.10 1995/08/17 20:35:52 jbk
|
||||
* fixed the debug macro to work with -pendantic option (yuck)
|
||||
*
|
||||
* Revision 1.9 1995/08/17 19:44:08 jbk
|
||||
* Added a new utility function to get the first of the year time stamp.
|
||||
*
|
||||
* Revision 1.8 1995/08/16 19:04:20 jbk
|
||||
* corrected vxworks time troubles
|
||||
*
|
||||
* Revision 1.7 1995/05/22 15:22:24 jbk
|
||||
* changes TS_EXTERN thing
|
||||
*
|
||||
* Revision 1.6 1995/02/01 15:30:17 winans
|
||||
* Added a type field to the configure command to disable the use of the event
|
||||
* system hardware if desired.
|
||||
*
|
||||
* Revision 1.5 1994/10/31 20:36:17 jbk
|
||||
* added new stuff
|
||||
*
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Author: Jim Kowalkowski
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 01-06-94 jbk initial version
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <timers.h>
|
||||
#include <semLib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <tsDefs.h>
|
||||
|
||||
#ifdef TS_DRIVER
|
||||
#define TS_EXTERN
|
||||
#else
|
||||
#define TS_EXTERN extern
|
||||
#endif
|
||||
|
||||
#define ER_EVENT_RESET_TICK 0x7d /* Reset the tick counter */
|
||||
|
||||
#define TS_MAGIC ('T'<<24|'S'<<16|'d'<<8|'r')
|
||||
#define TS_SLAVE_PORT 18322
|
||||
#define TS_MASTER_PORT 18323
|
||||
#define TS_RETRY_COUNT 4
|
||||
#define TS_TIME_OUT_MS 250
|
||||
#define TS_SECS_ASYNC_TRY_MASTER (60*5) /* every five minutes */
|
||||
#define TS_SECS_SYNC_TRY_MASTER (60*1) /* every one minute */
|
||||
|
||||
#define UDP_TIME_PORT 37
|
||||
#define UDP_NTP_PORT 123
|
||||
|
||||
#define TS_BILLION 1000000000
|
||||
#define TS_SYNC_RATE_SEC 10
|
||||
#define TS_CLOCK_RATE_HZ 1000
|
||||
#define TS_TOTAL_EVENTS 128
|
||||
/*Following is (SEC_IN_YEAR*90)+(22*SEC_IN_DAY) */
|
||||
/*22 is leap years from 1900 to 1990*/
|
||||
#define TS_1900_TO_EPICS_EPOCH 2840140800UL
|
||||
/*Following is (SEC_IN_YEAR*70)+(17*SEC_IN_DAY) */
|
||||
/*17 is leap years from 1900 to 1970*/
|
||||
#define TS_1900_TO_VXWORKS_EPOCH 2208988800UL
|
||||
/*Following is (SEC_IN_YEAR*20)+(5*SEC_IN_DAY) */
|
||||
/*5 is leap years from 1970 to 1990*/
|
||||
#define TS_VXWORKS_TO_EPICS_EPOCH 631152000UL
|
||||
|
||||
#define TS_STAMP_SERVER_PRI 70
|
||||
#define TS_SYNC_SERVER_PRI 70
|
||||
#define TS_SYNC_CLIENT_PRI 70
|
||||
#define TS_ASYNC_CLIENT_PRI 70
|
||||
|
||||
typedef enum { TS_time_request, TS_sync_request, TS_sync_msg } TStype;
|
||||
typedef enum { TS_master_alive, TS_master_dead } TSstate;
|
||||
typedef enum { TS_async_none, TS_async_private,
|
||||
TS_async_ntp, TS_async_time } TStime_protocol;
|
||||
typedef enum { TS_sync_master, TS_async_master,
|
||||
TS_sync_slave, TS_async_slave,
|
||||
TS_direct_master, TS_direct_slave} TStime_type;
|
||||
|
||||
struct TSstampTransStruct {
|
||||
unsigned long magic; /* identifier */
|
||||
TStype type; /* transaction type */
|
||||
struct timespec master_time; /* master time stamp - last sync time */
|
||||
struct timespec current_time; /* master current time stamp 1990 epoch */
|
||||
struct timespec unix_time; /* time using 1900 epoch */
|
||||
unsigned long sync_rate; /* master sends sync at this rate */
|
||||
unsigned long clock_hz; /* master clock this frequency (tick rate) */
|
||||
};
|
||||
typedef struct TSstampTransStruct TSstampTrans;
|
||||
|
||||
struct TSinfoStruct {
|
||||
TSstate state;
|
||||
TStime_type type;
|
||||
TStime_protocol async_type;
|
||||
int ts_sync_valid;
|
||||
|
||||
struct timespec *event_table; /* timestamp table */
|
||||
|
||||
unsigned long sync_rate; /* master send sync at this rate */
|
||||
unsigned long clock_hz; /* master clock is this frequency */
|
||||
unsigned long clock_conv;/* conversion factor for tick_rate->ns */
|
||||
unsigned long time_out; /* udp packet time-out in milliseconds */
|
||||
int master_timing_IOC; /* 1=master, 0=slave */
|
||||
int master_port; /* port that master listens on */
|
||||
int slave_port; /* port that slave listens on */
|
||||
int total_events; /* this is the total event in the event system*/
|
||||
int sync_event; /* this is the sync event number */
|
||||
int has_event_system; /* 1=has event system, 0=no event system */
|
||||
int has_direct_time; /* 1=has direct time, 0=no direct time */
|
||||
int UserRequestedType; /* let user force the setting of type */
|
||||
|
||||
SEM_ID sync_occurred;
|
||||
|
||||
struct sockaddr hunt; /* broadcast address info */
|
||||
struct sockaddr master; /* socket info for contacting master */
|
||||
};
|
||||
typedef struct TSinfoStruct TSinfo;
|
||||
|
||||
/* global functions */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
TS_EXTERN long TSinit(void);
|
||||
TS_EXTERN long TSgetTimeStamp(int event_number,struct timespec* ts);
|
||||
TS_EXTERN unsigned long TSepochNtpToUnix(struct timespec* ts);
|
||||
TS_EXTERN unsigned long TSfractionToNano(unsigned long fraction);
|
||||
TS_EXTERN unsigned long TSepochNtpToEpics(struct timespec* ts);
|
||||
TS_EXTERN unsigned long TSepochUnixToEpics(struct timespec* ts);
|
||||
TS_EXTERN unsigned long TSepochEpicsToUnix(struct timespec* ts);
|
||||
TS_EXTERN long TScurrentTimeStamp(struct timespec* ts);
|
||||
TS_EXTERN long TSaccurateTimeStamp(struct timespec* ts);
|
||||
TS_EXTERN long TSgetFirstOfYearVx(struct timespec* ts);
|
||||
TS_EXTERN void TSconfigure(int master, int sync_rate_sec, int clock_rate_hz,
|
||||
int master_port, int slave_port,
|
||||
unsigned long millisecond_request_time_out, int type);
|
||||
TS_EXTERN long TSsetClockFromUnix(void);
|
||||
|
||||
#ifndef TS_DRIVER
|
||||
TS_EXTERN TSinfo TSdata;
|
||||
TS_EXTERN TSdirectTimeVar; /* set to !=0 to indicate direct time available*/
|
||||
TS_EXTERN TSgoodTimeStamps; /* force best time stamps by setting != 0 */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
/* NTP information - all this is backwards and documentation only */
|
||||
#define VN_SHIFT 2 /* Version - 3 bits */
|
||||
#define VN_version 3<<VN_SHIFT
|
||||
|
||||
#define LI_SHIFT 0 /* Leap Indicator LI - 2 bits */
|
||||
#define LI_no_warning (0x00<<LI_SHIFT)
|
||||
#define LI_61_sec_minute (0x01<<LI_SHIFT)
|
||||
#define LI_59_sec_minute (0x02<<LI_SHIFT)
|
||||
#define LI_alarm_condition (0x03<<LI_SHIFT)
|
||||
|
||||
#define MODE_SHIFT 5 /* Mode MODE - 3 bits */
|
||||
#define MODE_reserved (0x00<<MODE_SHIFT)
|
||||
#define MODE_sym_active (0x01<<MODE_SHIFT)
|
||||
#define MODE_sym_passive (0x02<<MODE_SHIFT)
|
||||
#define MODE_client (0x03<<MODE_SHIFT)
|
||||
#define MODE_server (0x04<<MODE_SHIFT)
|
||||
#define MODE_broadcast (0x05<<MODE_SHIFT)
|
||||
#define MODE_reserved_NTP (0x06<<MODE_SHIFT)
|
||||
#define MODE_reserved_pvt (0x07<<MODE_SHIFT)
|
||||
|
||||
#define STRAT_SHIFT 8 /* Stratum STRAT - 8 bits */
|
||||
#define STRAT_unspecified (0x00<<STRAT_SHIFT)
|
||||
#define STRAT_ascii (0x00<<STRAT_SHIFT)
|
||||
#define STRAT_GPS (0x01<<STRAT_SHIFT)
|
||||
#define STRAT_ATOM (0x01<<STRAT_SHIFT)
|
||||
#define STRAT_address (0x02<<STRAT_SHIFT)
|
||||
|
||||
#define POLL_SHIFT 16 /* eight bits */
|
||||
#define PREC_SHIFT 24 /* eight bits */
|
||||
|
||||
struct TS_ntp {
|
||||
/* unsigned int info; */
|
||||
unsigned char info[4];
|
||||
unsigned int root_delay;
|
||||
unsigned int root_disp;
|
||||
unsigned int reference_id;
|
||||
struct timespec reference_ts;
|
||||
struct timespec originate_ts;
|
||||
struct timespec receive_ts;
|
||||
struct timespec transmit_ts;
|
||||
/* char authenticator[96]; (optional) */
|
||||
};
|
||||
typedef struct TS_ntp TS_NTP;
|
||||
|
||||
|
||||
/* debug macro creation */
|
||||
#ifdef NODEBUG
|
||||
#define Debug(l,f,v) ;
|
||||
#else
|
||||
#ifdef MAKE_DEBUG
|
||||
volatile int MAKE_DEBUG = 0;
|
||||
#define Debug(l,f,v) { if(l<= MAKE_DEBUG ) \
|
||||
{ printf("%s:%d: ",__FILE__,__LINE__); printf(f,v); }}
|
||||
#define Debug0(l,f) { if(l<= MAKE_DEBUG ) \
|
||||
{ printf("%s:%d: ",__FILE__,__LINE__); printf(f); }}
|
||||
#else
|
||||
#define Debug(l,f,v) { if(l) \
|
||||
{ printf("%s:%d: ",__FILE__,__LINE__); printf(f,v); }}
|
||||
#define Debug0(l,f) { if(l) \
|
||||
{ printf("%s:%d: ",__FILE__,__LINE__); printf(f); }}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,191 +0,0 @@
|
||||
/* fast_lock.h */
|
||||
/* share/epicsH $Id$ */
|
||||
|
||||
/*
|
||||
* Author: Jeff Hill
|
||||
* Date: 4-11-89
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 joh 041189 initial release into middle age
|
||||
* .02 joh 071989 added fast lock test
|
||||
* .03 joh 090391 VRTX kernel ifdef for V5 vxWorks
|
||||
* .04 joh 091091 Now uses V5 vxWorks binary semaphore
|
||||
* .05 joh 092491 Dont use V5 semaphore on V3 EPICS yet
|
||||
* .06 jba 030692 added cast to vxTas arg in FASTLOCK vxWorks5
|
||||
* .07 jba 081092 added cast to vxTas arg in FASTLOCKNOWAIT
|
||||
* .08 mgb 082493 Removed V5/V4 conditional defines
|
||||
* .09 joh 082493 include vxLib.h for vxWorks V5.1
|
||||
* .10 joh 082593 made lock char as vxTas expects
|
||||
* (padded structure to identical size)
|
||||
* .11 joh 082593 made fast lock structure fields volatile
|
||||
* .12 joh 091493 added sem and task lock based fast locks
|
||||
* with ifdefs - removed volatile
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Macros and data structures for a much faster (than vrtx semaphore)
|
||||
* mutual exclusion lock/unlock.
|
||||
* (semaphore in this case is only used to wait for unlock)
|
||||
*
|
||||
* On a 68020 the following times include lock and unlock
|
||||
*
|
||||
* FASTLOCK-FASTUNLOCK 8 microsecs
|
||||
* semTake-semGive(Macro) 80 microsecs
|
||||
* semTake-semGive 92 microsecs
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLfast_lockh
|
||||
#define INCLfast_lockh
|
||||
|
||||
#ifndef INCLsemLibh
|
||||
#include <semLib.h>
|
||||
#endif
|
||||
#ifndef INCLvxLibh
|
||||
#include <vxLib.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macro equivalent of vxWorks glue for better performance
|
||||
*/
|
||||
#ifdef VRTX_KERNEL
|
||||
# define semGive(SEMID)\
|
||||
{ if ((SEMID)->count == 0)vrtxPost (&((SEMID)->count), 1); }
|
||||
|
||||
# define semTake(SEMID)\
|
||||
{int dummy; vrtxPend (&((SEMID)->count), 0, &dummy); }
|
||||
#endif
|
||||
|
||||
typedef struct{
|
||||
SEM_ID ppend; /* wait for lock sem */
|
||||
unsigned short count; /* cnt of tasks waiting for lock */
|
||||
unsigned char lock; /* test and set lock bit */
|
||||
char pad; /* structure alignment */
|
||||
}FAST_LOCK;
|
||||
|
||||
#define SEM_FAST_LOCK
|
||||
|
||||
#if defined(SEM_FAST_LOCK) /* no lock test */
|
||||
|
||||
#define FASTLOCKINIT(PFAST_LOCK)\
|
||||
(((FAST_LOCK *)(PFAST_LOCK))->ppend = \
|
||||
semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY))
|
||||
#define FASTLOCKFREE(PFAST_LOCK)\
|
||||
semDelete( ((FAST_LOCK *)(PFAST_LOCK))->ppend )
|
||||
#define FASTLOCK(PFAST_LOCK)\
|
||||
semTake(((FAST_LOCK *)(PFAST_LOCK))->ppend, WAIT_FOREVER);
|
||||
#define FASTUNLOCK(PFAST_LOCK)\
|
||||
semGive(((FAST_LOCK *)(PFAST_LOCK))->ppend);
|
||||
#define FASTLOCKNOWAIT(PFAST_LOCK) \
|
||||
((semTake(((FAST_LOCK *)(PFAST_LOCK))->ppend,NO_WAIT)==0) ? TRUE : FALSE)
|
||||
#define FASTLOCKTEST(PFAST_LOCK) \
|
||||
(\
|
||||
(semTake(((FAST_LOCK *)(PFAST_LOCK))->ppend,NO_WAIT)==0 )\
|
||||
? (semGive(((FAST_LOCK *)(PFAST_LOCK))->ppend),FALSE)\
|
||||
: TRUE \
|
||||
)
|
||||
|
||||
|
||||
#elif defined(TASK_LOCK_FAST_LOCK)
|
||||
|
||||
#define FASTLOCKINIT(PFAST_LOCK)\
|
||||
(\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->count =0, \
|
||||
((FAST_LOCK *)(PFAST_LOCK))->lock =0, \
|
||||
((FAST_LOCK *)(PFAST_LOCK))->ppend = \
|
||||
semBCreate(SEM_Q_PRIORITY, SEM_EMPTY) \
|
||||
)
|
||||
#define FASTLOCKFREE(PFAST_LOCK)\
|
||||
semDelete( ((FAST_LOCK *)(PFAST_LOCK))->ppend )
|
||||
|
||||
#define FASTLOCK(PFAST_LOCK)\
|
||||
{\
|
||||
TASK_LOCK;\
|
||||
while( ((FAST_LOCK *)(PFAST_LOCK))->lock ){\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->count++;\
|
||||
TASK_UNLOCK;\
|
||||
semTake(((FAST_LOCK *)(PFAST_LOCK))->ppend, WAIT_FOREVER);\
|
||||
TASK_LOCK;\
|
||||
(((FAST_LOCK *)(PFAST_LOCK))->count)--;\
|
||||
}\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->lock= TRUE;
|
||||
TASK_UNLOCK;
|
||||
}
|
||||
|
||||
#define FASTUNLOCK(PFAST_LOCK)\
|
||||
{\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->lock = FALSE;\
|
||||
if( ((FAST_LOCK *)(PFAST_LOCK))->count )\
|
||||
semGive(((FAST_LOCK *)(PFAST_LOCK))->ppend);\
|
||||
};
|
||||
|
||||
#define FASTLOCKTEST(PFAST_LOCK)\
|
||||
( ((FAST_LOCK *)(PFAST_LOCK))->lock )
|
||||
|
||||
#else /* vxTas() fast lock */
|
||||
|
||||
/*
|
||||
* extra paren avoids order of ops problems
|
||||
* (returns what semBCreate returns on v5 vxWorks)
|
||||
*/
|
||||
#define FASTLOCKINIT(PFAST_LOCK)\
|
||||
(\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->count =0, \
|
||||
((FAST_LOCK *)(PFAST_LOCK))->lock =0, \
|
||||
((FAST_LOCK *)(PFAST_LOCK))->ppend = \
|
||||
semBCreate(SEM_Q_PRIORITY, SEM_EMPTY) \
|
||||
)
|
||||
|
||||
/*
|
||||
* new requirement with v5 vxWorks
|
||||
*/
|
||||
#define FASTLOCKFREE(PFAST_LOCK)\
|
||||
semDelete( ((FAST_LOCK *)(PFAST_LOCK))->ppend )
|
||||
|
||||
#define FASTLOCK(PFAST_LOCK)\
|
||||
{\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->count++;\
|
||||
while(!vxTas( (char *)&( ((FAST_LOCK *)(PFAST_LOCK))->lock ) ))\
|
||||
semTake(((FAST_LOCK *)(PFAST_LOCK))->ppend, WAIT_FOREVER);\
|
||||
( ((FAST_LOCK *)(PFAST_LOCK))->count)--;\
|
||||
}
|
||||
|
||||
#define FASTUNLOCK(PFAST_LOCK)\
|
||||
{\
|
||||
((FAST_LOCK *)(PFAST_LOCK))->lock = FALSE;\
|
||||
if( ((FAST_LOCK *)(PFAST_LOCK))->count )\
|
||||
semGive(((FAST_LOCK *)(PFAST_LOCK))->ppend);\
|
||||
};
|
||||
|
||||
#define FASTLOCKNOWAIT(PFAST_LOCK) (vxTas((char *)&(((FAST_LOCK *)(PFAST_LOCK))->lock)))
|
||||
|
||||
#define FASTLOCKTEST(PFAST_LOCK)\
|
||||
( ((FAST_LOCK *)(PFAST_LOCK))->lock )
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* Nothing after this endif */
|
||||
@@ -36,12 +36,12 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <ellLib.h>
|
||||
#include <initHooks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ellLib.h"
|
||||
#include "initHooks.h"
|
||||
|
||||
typedef struct initHookLink {
|
||||
ELLNODE node;
|
||||
|
||||
@@ -39,14 +39,13 @@
|
||||
|
||||
typedef enum {
|
||||
initHookAtBeginning,
|
||||
initHookAfterGetResources,
|
||||
initHookAfterLogInit,
|
||||
initHookAfterCallbackInit,
|
||||
initHookAfterCaLinkInit,
|
||||
initHookAfterInitDrvSup,
|
||||
initHookAfterInitRecSup,
|
||||
initHookAfterInitDevSup,
|
||||
initHookAfterTS_init,
|
||||
initHookAfterClockInit,
|
||||
initHookAfterInitDatabase,
|
||||
initHookAfterFinishDevSup,
|
||||
initHookAfterScanInit,
|
||||
|
||||
764
src/db/iocInit.c
764
src/db/iocInit.c
@@ -1,31 +1,14 @@
|
||||
/* iocInit.c ioc initialization */
|
||||
/* base/src/db $Id$ */
|
||||
/*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 06-01-91
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
/* Author: Marty Kraimer Date: 06-01-91 */
|
||||
|
||||
/********************COPYRIGHT NOTIFICATION**********************************
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
****************************************************************************/
|
||||
|
||||
/* Modification Log:
|
||||
* -----------------
|
||||
* .01 07-20-91 rac print release data; set env params
|
||||
* .02 08-06-91 mrk parm string length test changed to warning
|
||||
@@ -44,7 +27,7 @@
|
||||
* .14 04-17-92 mrk Added wait before interruptAccept
|
||||
* .15 05-17-92 rcz moved sdrSum stuff to dbReadWrite.c
|
||||
* .16 05-19-92 mrk Changes for internal database structure changes
|
||||
* .17 06-16-92 jba Added prset test to call of init_record second time loop
|
||||
* .17 06-16-92 jba prset test to call of init_record second time
|
||||
* .18 07-31-92 rcz moved database loading to function dbLoad
|
||||
* .19 08-14-92 jba included dblinks with maximize severity in lockset
|
||||
* .20 08-27-92 mrk removed wakeup_init (For old I/O Event scanning)
|
||||
@@ -61,48 +44,39 @@
|
||||
* .31 02-10-95 joh static => LOCAL
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sysLib.h>
|
||||
#include <symLib.h>
|
||||
#include <sysSymTbl.h> /* for sysSymTbl*/
|
||||
#include <logLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <envLib.h>
|
||||
#include <errnoLib.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "ellLib.h"
|
||||
#include "fast_lock.h"
|
||||
#include "dbDefs.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbScan.h"
|
||||
#include "taskwd.h"
|
||||
#include "callback.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "devSup.h"
|
||||
#include "drvSup.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "envDefs.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "initHooks.h"
|
||||
#include "drvTS.h"
|
||||
#include "asLib.h"
|
||||
|
||||
/*This module will declare and initilize module_type variables*/
|
||||
#define MODULE_TYPES_INIT 1
|
||||
#include <module_types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "osiThread.h"
|
||||
#include "osiClock.h"
|
||||
#include "osiSem.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbDefs.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbScan.h"
|
||||
#include "taskwd.h"
|
||||
#include "callback.h"
|
||||
#include "dbCommon.h"
|
||||
#include "dbLock.h"
|
||||
#include "dbFldTypes.h"
|
||||
#include "devSup.h"
|
||||
#include "drvSup.h"
|
||||
#include "registryRecordType.h"
|
||||
#include "registryDeviceSupport.h"
|
||||
#include "registryDriverSupport.h"
|
||||
#include "errMdef.h"
|
||||
#include "recSup.h"
|
||||
#include "envDefs.h"
|
||||
#include "dbStaticLib.h"
|
||||
#include "initHooks.h"
|
||||
#include "asLib.h"
|
||||
|
||||
LOCAL int initialized=FALSE;
|
||||
|
||||
@@ -112,276 +86,147 @@ volatile int interruptAccept=FALSE;
|
||||
struct dbBase *pdbbase=NULL;
|
||||
|
||||
/* define forward references*/
|
||||
LOCAL long initDrvSup(void);
|
||||
LOCAL long initRecSup(void);
|
||||
LOCAL long initDevSup(void);
|
||||
LOCAL long finishDevSup(void);
|
||||
LOCAL long initDatabase(void);
|
||||
LOCAL long initialProcess(void);
|
||||
LOCAL long getResources(char *fname);
|
||||
LOCAL int getResourceToken(FILE *fp, char *pToken, unsigned maxToken);
|
||||
LOCAL int getResourceTokenInternal(FILE *fp, char *pToken, unsigned maxToken);
|
||||
LOCAL void initDrvSup(void);
|
||||
LOCAL void initRecSup(void);
|
||||
LOCAL void initDevSup(void);
|
||||
LOCAL void finishDevSup(void);
|
||||
LOCAL void initDatabase(void);
|
||||
LOCAL void initialProcess(void);
|
||||
|
||||
|
||||
/*
|
||||
* Initialize EPICS on the IOC.
|
||||
*/
|
||||
int iocInit(char * pResourceFilename)
|
||||
int iocInit()
|
||||
{
|
||||
long status;
|
||||
char name[40];
|
||||
long rtnval;
|
||||
void (*pinitHooks)() = NULL;
|
||||
SYM_TYPE type;
|
||||
|
||||
if (initialized) {
|
||||
epicsPrintf("iocInit can only be called once\n");
|
||||
errlogPrintf("iocInit can only be called once\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
epicsPrintf("Starting iocInit\n");
|
||||
errlogPrintf("Starting iocInit\n");
|
||||
if (!pdbbase) {
|
||||
epicsPrintf("iocInit aborting because No database\n");
|
||||
errlogPrintf("iocInit aborting because No database\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Setup initialization hooks, if initHooks routine has been defined. */
|
||||
strcpy(name, "_");
|
||||
strcat(name, "initHooks");
|
||||
rtnval = symFindByNameEPICS(sysSymTbl, name, (void *) &pinitHooks, &type);
|
||||
if (pinitHooks) (*pinitHooks)(initHookAtBeginning);
|
||||
|
||||
initHooks(initHookAtBeginning);
|
||||
coreRelease();
|
||||
status = getResources(pResourceFilename);
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterGetResources);
|
||||
|
||||
status = iocLogInit();
|
||||
if (status!=0) {
|
||||
epicsPrintf("iocInit Failed to Initialize Ioc Log Client \n");
|
||||
}
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterLogInit);
|
||||
|
||||
|
||||
/* After this point, further calls to iocInit() are disallowed. */
|
||||
iocLogInit(); initHooks(initHookAfterLogInit);
|
||||
/* After this point, further calls to iocInit() are disallowed. */
|
||||
initialized = TRUE;
|
||||
|
||||
/*
|
||||
* Initialize the watchdog task. These is different from vxWorks watchdogs,
|
||||
* this task is assigned to watching and reporting if the vxWorks tasks
|
||||
* (that it has been told to watch) are suspended.
|
||||
*/
|
||||
taskwdInit();
|
||||
|
||||
callbackInit();
|
||||
/* let threads start */
|
||||
threadSleep(.1);
|
||||
initHooks(initHookAfterCallbackInit);
|
||||
dbCaLinkInit(); initHooks(initHookAfterCaLinkInit);
|
||||
initDrvSup(); initHooks(initHookAfterInitDrvSup);
|
||||
initRecSup(); initHooks(initHookAfterInitRecSup);
|
||||
initDevSup(); initHooks(initHookAfterInitDevSup);
|
||||
clockInit(); initHooks(initHookAfterClockInit);
|
||||
|
||||
/* Wait 1/10 second for above initializations to complete*/
|
||||
(void)taskDelay(sysClkRateGet()/10);
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterCallbackInit);
|
||||
|
||||
/* Initialize Channel Access Link mechanism. */
|
||||
dbCaLinkInit();
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterCaLinkInit);
|
||||
|
||||
if (initDrvSup() != 0)
|
||||
epicsPrintf("iocInit: Drivers Failed during Initialization\n");
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterInitDrvSup);
|
||||
|
||||
if (initRecSup() != 0)
|
||||
epicsPrintf("iocInit: Record Support Failed during Initialization\n");
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterInitRecSup);
|
||||
|
||||
if (initDevSup() != 0)
|
||||
epicsPrintf("iocInit: Device Support Failed during Initialization\n");
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterInitDevSup);
|
||||
|
||||
TSinit(); /* new time stamp driver (jbk) */
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterTS_init);
|
||||
|
||||
/* initialize database records */
|
||||
if (initDatabase() != 0)
|
||||
epicsPrintf("iocInit: Database Failed during Initialization\n");
|
||||
|
||||
initDatabase();
|
||||
dbLockInitRecords(pdbbase);
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterInitDatabase);
|
||||
initHooks(initHookAfterInitDatabase);
|
||||
|
||||
if (finishDevSup() != 0)
|
||||
epicsPrintf("iocInit: Device Support Failed during Finalization\n");
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterFinishDevSup);
|
||||
finishDevSup(); initHooks(initHookAfterFinishDevSup);
|
||||
|
||||
scanInit();
|
||||
if(asInit()) {
|
||||
epicsPrintf("iocInit: asInit Failed during initialization\n");
|
||||
errlogPrintf("iocInit: asInit Failed during initialization\n");
|
||||
return(-1);
|
||||
}
|
||||
(void)taskDelay(sysClkRateGet()/2);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterScanInit);
|
||||
threadSleep(.5);
|
||||
initHooks(initHookAfterScanInit);
|
||||
|
||||
/* Enable scan tasks and some driver support functions. */
|
||||
interruptAccept=TRUE;
|
||||
interruptAccept=TRUE; initHooks(initHookAfterInterruptAccept);
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterInterruptAccept);
|
||||
|
||||
/*
|
||||
* Process all records that have their "process at initialization"
|
||||
* field set (pini).
|
||||
*/
|
||||
if (initialProcess() != 0)
|
||||
epicsPrintf("iocInit: initialProcess Failed\n");
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(initHookAfterInitialProcess);
|
||||
initialProcess(); initHooks(initHookAfterInitialProcess);
|
||||
|
||||
/* Start up CA server */
|
||||
rsrv_init();
|
||||
|
||||
epicsPrintf("iocInit: All initialization complete\n");
|
||||
|
||||
if (pinitHooks) (*pinitHooks)(initHookAtEnd);
|
||||
|
||||
errlogPrintf("iocInit: All initialization complete\n");
|
||||
initHooks(initHookAtEnd);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize Driver Support
|
||||
* Locate all driver support entry tables.
|
||||
* Call the initialization routine (init) for each
|
||||
* driver type.
|
||||
*/
|
||||
LOCAL long initDrvSup(void) /* Locate all driver support entry tables */
|
||||
LOCAL void initDrvSup(void) /* Locate all driver support entry tables */
|
||||
{
|
||||
char name[40];
|
||||
SYM_TYPE type;
|
||||
long status=0;
|
||||
long rtnval;
|
||||
STATUS vxstatus;
|
||||
drvSup *pdrvSup;
|
||||
struct drvet *pdrvet;
|
||||
|
||||
/*
|
||||
* For every driver support module, look up the name
|
||||
* for that function in the vxWorks symbol table. If
|
||||
* a driver entry table doesn't exist, report that
|
||||
* fact.
|
||||
*/
|
||||
for(pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList); pdrvSup;
|
||||
pdrvSup = (drvSup *)ellNext(&pdrvSup->node)) {
|
||||
strcpy(name,"_");
|
||||
strcat(name,pdrvSup->name);
|
||||
vxstatus = symFindByNameEPICS(sysSymTbl, name,
|
||||
(void *) &pdrvet, &type);
|
||||
if (vxstatus != OK) {
|
||||
status = S_drv_noDrvet;
|
||||
errPrintf(status,__FILE__,__LINE__,"%s",pdrvSup->name);
|
||||
pdrvet = registryDriverSupportFind(pdrvSup->name);
|
||||
if(pdrvet==0) {
|
||||
errlogPrintf("iocInit: driver %s not found\n",pdrvSup->name);
|
||||
continue;
|
||||
}
|
||||
pdrvSup->pdrvet = pdrvet;
|
||||
pdrvSup->pdrvet = pdrvet;
|
||||
/*
|
||||
* If an initialization routine is defined (not NULL),
|
||||
* for the driver support call it.
|
||||
*/
|
||||
if (!pdrvet->init) continue;
|
||||
rtnval = (*(pdrvet->init))();
|
||||
if (status == 0) status = rtnval;
|
||||
if(pdrvet->init) (*(pdrvet->init))();
|
||||
}
|
||||
return(status);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize Record Support
|
||||
* Allocate a record support structure for every record type
|
||||
* plus space for an array of pointers to RSETs.
|
||||
* Locate all record support entry tables.
|
||||
* Call the initialization routine (init) for each
|
||||
* record type.
|
||||
*/
|
||||
LOCAL long initRecSup(void)
|
||||
|
||||
LOCAL void initRecSup(void)
|
||||
{
|
||||
char name[60];
|
||||
SYM_TYPE type;
|
||||
long status=0;
|
||||
long rtnval;
|
||||
STATUS vxstatus;
|
||||
dbRecordType *pdbRecordType;
|
||||
dbRecordType *pdbRecordType;
|
||||
recordTypeLocation *precordTypeLocation;
|
||||
struct rset *prset;
|
||||
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
|
||||
strcpy(name,"_");
|
||||
strcat(name,pdbRecordType->name);
|
||||
strcat(name,"RSET");
|
||||
vxstatus = symFindByNameEPICS(sysSymTbl, name,
|
||||
(void *)&pdbRecordType->prset, &type);
|
||||
if (vxstatus != OK) {
|
||||
status = S_rec_noRSET;
|
||||
errPrintf(status,__FILE__,__LINE__,"%s",pdbRecordType->name);
|
||||
precordTypeLocation = registryRecordTypeFind(pdbRecordType->name);
|
||||
if (precordTypeLocation==0) {
|
||||
errlogPrintf("iocInit record support for %s not found\n",
|
||||
pdbRecordType->name);
|
||||
continue;
|
||||
}
|
||||
prset = pdbRecordType->prset;
|
||||
/* If an initialization routine exists for a record type, execute it */
|
||||
if(!prset->init) {
|
||||
continue;
|
||||
} else {
|
||||
rtnval = (*prset->init)();
|
||||
if (status==0)
|
||||
status = rtnval;
|
||||
}
|
||||
prset = precordTypeLocation->prset;
|
||||
pdbRecordType->prset = prset;
|
||||
if(prset->init) (*prset->init)();
|
||||
}
|
||||
return(status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize Device Support
|
||||
* Locate all device support entry tables.
|
||||
* Call the initialization routine (init) for each
|
||||
* device type (First Pass).
|
||||
*/
|
||||
LOCAL long initDevSup(void)
|
||||
LOCAL void initDevSup(void)
|
||||
{
|
||||
char *pname;
|
||||
char name[40];
|
||||
SYM_TYPE type;
|
||||
long status=0;
|
||||
long rtnval = 0;
|
||||
STATUS vxstatus;
|
||||
dbRecordType *pdbRecordType;
|
||||
devSup *pdevSup;
|
||||
struct dset *pdset;
|
||||
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
|
||||
for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup;
|
||||
pdevSup = (devSup *)ellNext(&pdevSup->node)) {
|
||||
if(!(pname = pdevSup->name)) continue;
|
||||
strcpy(name, "_");
|
||||
strcat(name, pname);
|
||||
vxstatus = (long) symFindByNameEPICS(sysSymTbl, name,
|
||||
(void *) &pdset, &type);
|
||||
if (vxstatus != OK) {
|
||||
status = S_dev_noDSET;
|
||||
errPrintf(status,__FILE__,__LINE__,"%s",pdevSup->name);
|
||||
pdset = registryDeviceSupportFind(pdevSup->name);
|
||||
if (pdset==0) {
|
||||
errlogPrintf("device support %s not found\n",pdevSup->name);
|
||||
continue;
|
||||
}
|
||||
pdevSup->pdset = pdset;
|
||||
if(!(pdset->init)) continue;
|
||||
rtnval = (*pdset->init)(0);
|
||||
if (status == 0) status = rtnval;
|
||||
if(pdset->init) (*pdset->init)(0);
|
||||
}
|
||||
}
|
||||
return(status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calls the second pass for each device support
|
||||
* initialization routine. The second pass is made
|
||||
* after the database records have been initialized and
|
||||
* placed into lock sets.
|
||||
*/
|
||||
LOCAL long finishDevSup(void)
|
||||
LOCAL void finishDevSup(void)
|
||||
{
|
||||
dbRecordType *pdbRecordType;
|
||||
devSup *pdevSup;
|
||||
struct dset *pdset;
|
||||
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
|
||||
for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup;
|
||||
pdevSup = (devSup *)ellNext(&pdevSup->node)) {
|
||||
@@ -390,14 +235,12 @@ LOCAL long finishDevSup(void)
|
||||
}
|
||||
|
||||
}
|
||||
return(0);
|
||||
return;
|
||||
}
|
||||
|
||||
LOCAL long initDatabase(void)
|
||||
LOCAL void initDatabase(void)
|
||||
{
|
||||
long status=0;
|
||||
long rtnval=0;
|
||||
dbRecordType *pdbRecordType;
|
||||
dbRecordType *pdbRecordType;
|
||||
dbFldDes *pdbFldDes;
|
||||
dbRecordNode *pdbRecordNode;
|
||||
devSup *pdevSup;
|
||||
@@ -408,7 +251,8 @@ LOCAL long initDatabase(void)
|
||||
DBLINK *plink;
|
||||
int j;
|
||||
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
|
||||
prset = pdbRecordType->prset;
|
||||
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
|
||||
@@ -420,7 +264,7 @@ LOCAL long initDatabase(void)
|
||||
if(!(precord->name[0])) continue;
|
||||
precord->rset = prset;
|
||||
precord->rdes = pdbRecordType;
|
||||
FASTLOCKINIT(&precord->mlok);
|
||||
precord->mlok = semMutexCreate();
|
||||
ellInit(&(precord->mlis));
|
||||
|
||||
/* Reset the process active field */
|
||||
@@ -430,16 +274,14 @@ LOCAL long initDatabase(void)
|
||||
pdevSup = (devSup *)ellNth(&pdbRecordType->devList,precord->dtyp+1);
|
||||
pdset = (pdevSup ? pdevSup->pdset : 0);
|
||||
precord->dset = pdset;
|
||||
if(!prset->init_record) continue;
|
||||
rtnval = (*prset->init_record)(precord,0);
|
||||
if (status==0) status = rtnval;
|
||||
if(prset->init_record) (*prset->init_record)(precord,0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Second pass to resolve links
|
||||
*/
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
|
||||
|
||||
/* initDatabse cont. */
|
||||
/* Second pass to resolve links */
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
|
||||
prset = pdbRecordType->prset;
|
||||
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
|
||||
@@ -480,7 +322,8 @@ LOCAL long initDatabase(void)
|
||||
}
|
||||
|
||||
/* Call record support init_record routine - Second pass */
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType;
|
||||
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) {
|
||||
prset = pdbRecordType->prset;
|
||||
for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList);
|
||||
@@ -491,19 +334,17 @@ LOCAL long initDatabase(void)
|
||||
precord = pdbRecordNode->precord;
|
||||
if(!(precord->name[0])) continue;
|
||||
precord->rset = prset;
|
||||
if(!prset->init_record) continue;
|
||||
rtnval = (*prset->init_record)(precord,1);
|
||||
if (status==0) status = rtnval;
|
||||
if(prset->init_record) (*prset->init_record)(precord,1);
|
||||
}
|
||||
}
|
||||
return(status);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process database records at initialization if
|
||||
* their pini (process at init) field is set.
|
||||
*/
|
||||
LOCAL long initialProcess(void)
|
||||
LOCAL void initialProcess(void)
|
||||
{
|
||||
dbRecordType *pdbRecordType;
|
||||
dbRecordNode *pdbRecordNode;
|
||||
@@ -521,366 +362,21 @@ LOCAL long initialProcess(void)
|
||||
(void)dbProcess(precord);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int dbLoadDatabase(char *filename,char *path,char *substitutions)
|
||||
{
|
||||
return(dbReadDatabase(&pdbbase,filename,path,substitutions));
|
||||
int status;
|
||||
status = dbReadDatabase(&pdbbase,filename,path,substitutions);
|
||||
if(status) return(status);
|
||||
status = registerRecordDeviceDriver(pdbbase);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*Remaining code supplied by Bob Zieman*/
|
||||
#define MAX 256
|
||||
#define SAME 0
|
||||
|
||||
enum resType {
|
||||
resDBF_STRING,
|
||||
resDBF_SHORT,
|
||||
resDBF_LONG,
|
||||
resDBF_FLOAT,
|
||||
resDBF_DOUBLE,
|
||||
resInvalid};
|
||||
LOCAL char *cvt_str[] = {
|
||||
"DBF_STRING",
|
||||
"DBF_SHORT",
|
||||
"DBF_LONG",
|
||||
"DBF_FLOAT",
|
||||
"DBF_DOUBLE",
|
||||
"Invalid",
|
||||
};
|
||||
|
||||
#define EPICS_ENV_PREFIX "EPICS_"
|
||||
|
||||
long getResources(char *fname)
|
||||
int dbLoadRecords(char* pfilename, char* substitutions)
|
||||
{
|
||||
char s1[MAX];
|
||||
char s2[MAX];
|
||||
char s3[MAX];
|
||||
char name[40];
|
||||
FILE *fp;
|
||||
enum resType cvType = resInvalid;
|
||||
int epicsFlag;
|
||||
SYM_TYPE type;
|
||||
char *pSymAddr;
|
||||
short n_short;
|
||||
long n_long;
|
||||
float n_float;
|
||||
double n_double;
|
||||
int status;
|
||||
|
||||
if (!fname) return (0);
|
||||
|
||||
if ((fp = fopen(fname, "r")) == 0) {
|
||||
errPrintf(
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"No such Resource file - %s",
|
||||
fname);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
status = getResourceToken (fp, s1, sizeof(s1));
|
||||
if (status<0) {
|
||||
/*
|
||||
* EOF
|
||||
*/
|
||||
break;
|
||||
}
|
||||
status = getResourceToken (fp, s2, sizeof(s2));
|
||||
if (status<0) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Missing resource data type field for resource=%s in file=%s",
|
||||
s1,
|
||||
fname);
|
||||
break;
|
||||
}
|
||||
status = getResourceToken (fp, s3, sizeof(s3));
|
||||
if (status<0) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Missing resource value field for resource=%s data type=%s file=%s",
|
||||
s1,
|
||||
s2,
|
||||
fname);
|
||||
break; /* EOF */
|
||||
}
|
||||
|
||||
for (cvType = 0; cvType < resInvalid; cvType++) {
|
||||
if (strcmp(s2, cvt_str[cvType]) == SAME) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strcpy(name, "_");
|
||||
strcat(name, s1);
|
||||
status = symFindByNameEPICS(sysSymTbl, name, &pSymAddr, &type);
|
||||
if (status!= OK) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Matching Symbol name not found for resource=%s",
|
||||
s1);
|
||||
continue;
|
||||
}
|
||||
|
||||
status = strncmp (
|
||||
s1,
|
||||
EPICS_ENV_PREFIX,
|
||||
strlen (EPICS_ENV_PREFIX));
|
||||
if (status == SAME) {
|
||||
epicsFlag = 1;
|
||||
if (cvType != resDBF_STRING) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"%s should be set with type DBF_STRING not type %s",
|
||||
s1,
|
||||
s2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsFlag = 0;
|
||||
}
|
||||
|
||||
switch (cvType) {
|
||||
case resDBF_STRING:
|
||||
if ( epicsFlag ) {
|
||||
char *pEnv;
|
||||
|
||||
/*
|
||||
* space for two strings, an '=' character,
|
||||
* and a null termination
|
||||
*/
|
||||
pEnv = malloc (strlen (s3) + strlen (s1) + 2);
|
||||
if (!pEnv) {
|
||||
errPrintf(
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Failed to set environment parameter \"%s\" to \"%s\" because \"%s\"\n",
|
||||
s1,
|
||||
s3,
|
||||
strerror (errnoGet()));
|
||||
break;
|
||||
}
|
||||
strcpy (pEnv, s1);
|
||||
strcat (pEnv, "=");
|
||||
strcat (pEnv, s3);
|
||||
status = putenv (pEnv);
|
||||
if (status<0) {
|
||||
errPrintf(
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Failed to set environment parameter \"%s\" to \"%s\" because \"%s\"\n",
|
||||
s1,
|
||||
s3,
|
||||
strerror (errnoGet()));
|
||||
}
|
||||
/*
|
||||
* vxWorks copies into a private buffer
|
||||
* (this does not match UNIX behavior)
|
||||
*/
|
||||
free (pEnv);
|
||||
}
|
||||
else{
|
||||
strcpy(pSymAddr, s3);
|
||||
}
|
||||
break;
|
||||
|
||||
case resDBF_SHORT:
|
||||
if (sscanf(s3, "%hd", &n_short) != 1) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Resource=%s value=%s conversion to %s failed",
|
||||
s1,
|
||||
s3,
|
||||
cvt_str[cvType]);
|
||||
continue;
|
||||
}
|
||||
*(short *) pSymAddr = n_short;
|
||||
break;
|
||||
|
||||
case resDBF_LONG:
|
||||
if (sscanf(s3, "%ld", &n_long) != 1) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Resource=%s value=%s conversion to %s failed",
|
||||
s1,
|
||||
s3,
|
||||
cvt_str[cvType]);
|
||||
continue;
|
||||
}
|
||||
*(long *) pSymAddr = n_long;
|
||||
break;
|
||||
|
||||
case resDBF_FLOAT:
|
||||
if (sscanf(s3, "%e", &n_float) != 1) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Resource=%s value=%s conversion to %s failed",
|
||||
s1,
|
||||
s3,
|
||||
cvt_str[cvType]);
|
||||
continue;
|
||||
}
|
||||
*(float *) pSymAddr = n_float;
|
||||
break;
|
||||
|
||||
case resDBF_DOUBLE:
|
||||
if (sscanf(s3, "%le", &n_double) != 1) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Resource=%s value=%s conversion to %s failed",
|
||||
s1,
|
||||
s3,
|
||||
cvt_str[cvType]);
|
||||
continue;
|
||||
}
|
||||
*(double *) pSymAddr = n_double;
|
||||
break;
|
||||
|
||||
default:
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Invalid data type field=%s for resource=%s",
|
||||
s2,
|
||||
s1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return (0);
|
||||
return(dbReadDatabase(&pdbbase,pfilename,0,substitutions));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* getResourceToken
|
||||
*/
|
||||
LOCAL int getResourceToken(FILE *fp, char *pToken, unsigned maxToken)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* keep reading until we get a token
|
||||
* (and comments have been stripped)
|
||||
*/
|
||||
while (TRUE) {
|
||||
status = getResourceTokenInternal (fp, pToken, maxToken);
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (pToken[0] != '\0') {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getResourceTokenInternal
|
||||
*/
|
||||
LOCAL int getResourceTokenInternal(FILE *fp, char *pToken, unsigned maxToken)
|
||||
{
|
||||
char formatString[32];
|
||||
char quoteCharString[2];
|
||||
int status;
|
||||
|
||||
quoteCharString[0] = '\0';
|
||||
status = fscanf (fp, " %1[\"`'!]", quoteCharString);
|
||||
if (status<0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (quoteCharString[0]) {
|
||||
/*
|
||||
* its a comment
|
||||
* (consume everything up to the next new line)
|
||||
*/
|
||||
case '!':
|
||||
{
|
||||
char tmp[MAX];
|
||||
|
||||
sprintf(formatString, "%%%d[^\n\r\v\f]", (int)(sizeof(tmp)-1));
|
||||
status = fscanf (fp, "%[^\n\r\v\f]",tmp);
|
||||
pToken[0] = '\0';
|
||||
if (status<0) {
|
||||
return status;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* its a plain token
|
||||
*/
|
||||
case '\0':
|
||||
sprintf(formatString, " %%%ds", maxToken-1);
|
||||
|
||||
status = fscanf (fp, formatString, pToken);
|
||||
if (status!=1) {
|
||||
if (status < 0){
|
||||
pToken[0] = '\0';
|
||||
return status;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* it was a quoted string
|
||||
*/
|
||||
default:
|
||||
sprintf(
|
||||
formatString,
|
||||
"%%%d[^%c]",
|
||||
maxToken-1,
|
||||
quoteCharString[0]);
|
||||
status = fscanf (fp, formatString, pToken);
|
||||
if (status!=1) {
|
||||
if (status < 0){
|
||||
pToken[0] = '\0';
|
||||
return status;
|
||||
}
|
||||
}
|
||||
sprintf(formatString, "%%1[%c]", quoteCharString[0]);
|
||||
status = fscanf (fp, formatString, quoteCharString);
|
||||
if (status!=1) {
|
||||
errPrintf (
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Resource file syntax error: unterminated string \"%s\"",
|
||||
pToken);
|
||||
pToken[0] = '\0';
|
||||
if (status < 0){
|
||||
return status;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -41,23 +41,23 @@
|
||||
* .11 03-21-94 mcn Added fast link routines
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <limits.h>
|
||||
#include <types.h>
|
||||
#include <stdioLib.h>
|
||||
#include <strLib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbScan.h"
|
||||
#include "devSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "dbCommon.h"
|
||||
#include "drvTS.h"
|
||||
#include "dbDefs.h"
|
||||
#include "osiClock.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "dbBase.h"
|
||||
#include "dbEvent.h"
|
||||
#include "dbAccess.h"
|
||||
#include "dbConvert.h"
|
||||
#include "dbScan.h"
|
||||
#include "devSup.h"
|
||||
#include "recGbl.h"
|
||||
#include "dbCommon.h"
|
||||
|
||||
|
||||
/* local routines */
|
||||
@@ -313,10 +313,10 @@ void recGblGetTimeStamp(void* prec)
|
||||
if(pr->tsel.type!=CONSTANT)
|
||||
{
|
||||
dbGetLink(&(pr->tsel), DBR_SHORT,&(pr->tse),0,0);
|
||||
TSgetTimeStamp((int)pr->tse,(struct timespec*)&pr->time);
|
||||
clockGetEventTime((int)pr->tse,&pr->time);
|
||||
}
|
||||
else
|
||||
TSgetTimeStamp((int)pr->tse,(struct timespec*)&pr->time);
|
||||
clockGetEventTime((int)pr->tse,&pr->time);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,11 +32,7 @@
|
||||
#define INCrecGblh 1
|
||||
|
||||
|
||||
#ifdef vxWorks
|
||||
#ifndef INCdbCommonh
|
||||
#include <dbCommon.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* One ABSOLUTELY must include dbAccess.h before the
|
||||
@@ -51,15 +47,6 @@
|
||||
#endif
|
||||
#include <dbFldTypes.h>
|
||||
|
||||
/*************************************************************************
|
||||
* The following must match definitions in global menu definitions
|
||||
*************************************************************************/
|
||||
|
||||
/* GBL_IVOA */
|
||||
#define IVOA_CONTINUE 0
|
||||
#define IVOA_NO_OUTPUT 1
|
||||
#define IVOA_OUTPUT_IVOV 2
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
#define recGblSetSevr(PREC,NSTA,NSEV) \
|
||||
|
||||
@@ -32,27 +32,24 @@
|
||||
* .02 05-04-94 mrk Allow user callback to call taskwdRemove
|
||||
*/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <vxLib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ellLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "errMdef.h"
|
||||
#include "taskwd.h"
|
||||
#include "task_params.h"
|
||||
#include "fast_lock.h"
|
||||
#include "dbDefs.h"
|
||||
#include "osiThread.h"
|
||||
#include "osiSem.h"
|
||||
#include "errlog.h"
|
||||
#include "ellLib.h"
|
||||
#include "errMdef.h"
|
||||
#include "taskwd.h"
|
||||
|
||||
struct task_list {
|
||||
ELLNODE node;
|
||||
VOIDFUNCPTR callback;
|
||||
void *arg;
|
||||
union {
|
||||
int tid;
|
||||
threadId tid;
|
||||
void *userpvt;
|
||||
} id;
|
||||
int suspended;
|
||||
@@ -60,15 +57,18 @@ struct task_list {
|
||||
|
||||
static ELLLIST list;
|
||||
static ELLLIST anylist;
|
||||
static FAST_LOCK lock;
|
||||
static FAST_LOCK anylock;
|
||||
static FAST_LOCK alloclock;
|
||||
static int taskwdid=0;
|
||||
static semId lock;
|
||||
static semId anylock;
|
||||
static semId alloclock;
|
||||
static threadId taskwdid=0;
|
||||
volatile int taskwdOn=TRUE;
|
||||
struct freeList{
|
||||
struct freeList *next;
|
||||
};
|
||||
static struct freeList *freeHead=NULL;
|
||||
/* Task delay times (seconds) */
|
||||
#define TASKWD_DELAY 6.0
|
||||
|
||||
|
||||
/*forward definitions*/
|
||||
static void taskwdTask(void);
|
||||
@@ -77,59 +77,59 @@ static void freeList(struct task_list *pt);
|
||||
|
||||
void taskwdInit()
|
||||
{
|
||||
FASTLOCKINIT(&lock);
|
||||
FASTLOCKINIT(&anylock);
|
||||
FASTLOCKINIT(&alloclock);
|
||||
lock = semMutexCreate();
|
||||
anylock = semMutexCreate();
|
||||
alloclock = semMutexCreate();
|
||||
ellInit(&list);
|
||||
ellInit(&anylist);
|
||||
taskwdid = taskSpawn(TASKWD_NAME,TASKWD_PRI,
|
||||
TASKWD_OPT,TASKWD_STACK,(FUNCPTR )taskwdTask,
|
||||
0,0,0,0,0,0,0,0,0,0);
|
||||
taskwdid = threadCreate(
|
||||
"taskwd",threadPriorityLow,threadGetStackSize(threadStackSmall),
|
||||
(THREADFUNC)taskwdTask,0);
|
||||
}
|
||||
|
||||
void taskwdInsert(int tid,VOIDFUNCPTR callback,void *arg)
|
||||
void taskwdInsert(threadId tid,VOIDFUNCPTR callback,void *arg)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&lock);
|
||||
semMutexTakeAssert(lock);
|
||||
pt = allocList();
|
||||
ellAdd(&list,(void *)pt);
|
||||
pt->suspended = FALSE;
|
||||
pt->id.tid = tid;
|
||||
pt->callback = callback;
|
||||
pt->arg = arg;
|
||||
FASTUNLOCK(&lock);
|
||||
semMutexGive(lock);
|
||||
}
|
||||
|
||||
void taskwdAnyInsert(void *userpvt,VOIDFUNCPTR callback,void *arg)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&anylock);
|
||||
semMutexTakeAssert(anylock);
|
||||
pt = allocList();
|
||||
ellAdd(&anylist,(void *)pt);
|
||||
pt->id.userpvt = userpvt;
|
||||
pt->callback = callback;
|
||||
pt->arg = arg;
|
||||
FASTUNLOCK(&anylock);
|
||||
semMutexGive(anylock);
|
||||
}
|
||||
|
||||
void taskwdRemove(int tid)
|
||||
void taskwdRemove(threadId tid)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&lock);
|
||||
semMutexTakeAssert(lock);
|
||||
pt = (struct task_list *)ellFirst(&list);
|
||||
while(pt!=NULL) {
|
||||
if (tid == pt->id.tid) {
|
||||
ellDelete(&list,(void *)pt);
|
||||
freeList(pt);
|
||||
FASTUNLOCK(&lock);
|
||||
semMutexGive(lock);
|
||||
return;
|
||||
}
|
||||
pt = (struct task_list *)ellNext((ELLNODE *)pt);
|
||||
}
|
||||
FASTUNLOCK(&lock);
|
||||
semMutexGive(lock);
|
||||
errMessage(-1,"taskwdRemove failed");
|
||||
}
|
||||
|
||||
@@ -137,18 +137,18 @@ void taskwdAnyRemove(void *userpvt)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&anylock);
|
||||
semMutexTakeAssert(anylock);
|
||||
pt = (struct task_list *)ellFirst(&anylist);
|
||||
while(pt!=NULL) {
|
||||
if (userpvt == pt->id.userpvt) {
|
||||
ellDelete(&anylist,(void *)pt);
|
||||
freeList(pt);
|
||||
FASTUNLOCK(&anylock);
|
||||
semMutexGive(anylock);
|
||||
return;
|
||||
}
|
||||
pt = (struct task_list *)ellNext((void *)pt);
|
||||
}
|
||||
FASTUNLOCK(&anylock);
|
||||
semMutexGive(anylock);
|
||||
errMessage(-1,"taskwdanyRemove failed");
|
||||
}
|
||||
|
||||
@@ -158,20 +158,20 @@ static void taskwdTask(void)
|
||||
|
||||
while(TRUE) {
|
||||
if(taskwdOn) {
|
||||
FASTLOCK(&lock);
|
||||
semMutexTakeAssert(lock);
|
||||
pt = (struct task_list *)ellFirst(&list);
|
||||
while(pt) {
|
||||
next = (struct task_list *)ellNext((void *)pt);
|
||||
if(taskIsSuspended(pt->id.tid)) {
|
||||
char *pname;
|
||||
if(threadIsSuspended(pt->id.tid)) {
|
||||
const char *pname;
|
||||
char message[100];
|
||||
|
||||
pname = taskName(pt->id.tid);
|
||||
pname = threadGetName(pt->id.tid);
|
||||
if(!pt->suspended) {
|
||||
struct task_list *ptany;
|
||||
|
||||
pt->suspended = TRUE;
|
||||
sprintf(message,"task %x %s suspended",pt->id.tid,pname);
|
||||
sprintf(message,"task %s suspended",pname);
|
||||
errMessage(-1,message);
|
||||
ptany = (struct task_list *)ellFirst(&anylist);
|
||||
while(ptany) {
|
||||
@@ -183,7 +183,7 @@ static void taskwdTask(void)
|
||||
void *arg = pt->arg;
|
||||
|
||||
/*Must allow callback to call taskwdRemove*/
|
||||
FASTUNLOCK(&lock);
|
||||
semMutexGive(lock);
|
||||
(pcallback)(arg);
|
||||
/*skip rest because we have unlocked*/
|
||||
break;
|
||||
@@ -194,9 +194,9 @@ static void taskwdTask(void)
|
||||
}
|
||||
pt = next;
|
||||
}
|
||||
FASTUNLOCK(&lock);
|
||||
semMutexGive(lock);
|
||||
}
|
||||
taskDelay(TASKWD_DELAY*vxTicksPerSecond);
|
||||
threadSleep(TASKWD_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ static struct task_list *allocList(void)
|
||||
{
|
||||
struct task_list *pt;
|
||||
|
||||
FASTLOCK(&alloclock);
|
||||
semMutexTakeAssert(alloclock);
|
||||
if(freeHead) {
|
||||
pt = (struct task_list *)freeHead;
|
||||
freeHead = freeHead->next;
|
||||
@@ -214,15 +214,15 @@ static struct task_list *allocList(void)
|
||||
errMessage(0,"taskwd failed on call to calloc\n");
|
||||
exit(1);
|
||||
}
|
||||
FASTUNLOCK(&alloclock);
|
||||
semMutexGive(alloclock);
|
||||
return(pt);
|
||||
}
|
||||
|
||||
static void freeList(struct task_list *pt)
|
||||
{
|
||||
|
||||
FASTLOCK(&alloclock);
|
||||
semMutexTakeAssert(alloclock);
|
||||
((struct freeList *)pt)->next = freeHead;
|
||||
freeHead = (struct freeList *)pt;
|
||||
FASTUNLOCK(&alloclock);
|
||||
semMutexGive(alloclock);
|
||||
}
|
||||
|
||||
@@ -35,11 +35,13 @@
|
||||
#ifndef INCtaskwdh
|
||||
#define INCtaskwdh 1
|
||||
|
||||
#include "osiThread.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
void taskwdInit();
|
||||
void taskwdInsert(int tid, VOIDFUNCPTR callback,void *arg);
|
||||
void taskwdInsert(threadId tid, VOIDFUNCPTR callback,void *arg);
|
||||
void taskwdAnyInsert(void *userpvt, VOIDFUNCPTR callback,void *arg);
|
||||
void taskwdRemove(int tid);
|
||||
void taskwdRemove(threadId tid);
|
||||
void taskwdAnyRemove(void *userpvt);
|
||||
#else
|
||||
void taskwdInit();
|
||||
|
||||
@@ -1,7 +1,46 @@
|
||||
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
include $(TOP)/config/RULES_ARCHS
|
||||
# includes to install from this sub-project
|
||||
#
|
||||
INC += alarm.h alarmString.h dbBase.h dbFldTypes.h
|
||||
INC += dbStaticLib.h link.h special.h guigroup.h
|
||||
|
||||
# Sources to compile & put into lib:
|
||||
#
|
||||
LIBSRCS := dbStaticLib.c dbYacc.c dbPvdLib.c dbStaticNoRun.c
|
||||
|
||||
# Library to build:
|
||||
#
|
||||
LIBRARY := Db
|
||||
|
||||
# Products to build:
|
||||
#
|
||||
PROD := dbReadTest dbExpand dbToMenuH dbToRecordtypeH
|
||||
|
||||
# libs needed by PROD:
|
||||
#
|
||||
PROD_LIBS := Db Com Osi
|
||||
|
||||
#====================================================
|
||||
|
||||
dbStaticLib_SRCS = \
|
||||
dbYacc.c\
|
||||
dbPvdLib.c\
|
||||
dbStaticRun.c\
|
||||
dbStaticLib.c
|
||||
|
||||
IOC_LIBRARY_vxWorks = dbStaticLib
|
||||
|
||||
#====================================================
|
||||
include $(TOP)/configure/RULES_BUILD
|
||||
|
||||
# Extra rule since dbLexRoutines.c is included in dbYacc.c
|
||||
dbYacc$(OBJ): dbLex.c ../dbLexRoutines.c
|
||||
|
||||
clean::
|
||||
@$(RM) dbLex.c dbYacc.c
|
||||
|
||||
# EOF Makefile.Host for base/src/dbStatic
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
# Makefile.Host for base/src/dbStatic
|
||||
#
|
||||
#
|
||||
TOP = ../../..
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
|
||||
# includes to install from this sub-project
|
||||
#
|
||||
INC += alarm.h alarmString.h dbBase.h dbFldTypes.h
|
||||
INC += dbStaticLib.h link.h special.h guigroup.h
|
||||
|
||||
# Sources to compile & put into lib:
|
||||
#
|
||||
LIBSRCS := dbStaticLib.c dbYacc.c dbPvdLib.c dbStaticNoRun.c
|
||||
|
||||
# Library to build:
|
||||
#
|
||||
LIBRARY := Db
|
||||
|
||||
# Products to build:
|
||||
#
|
||||
PROD := dbReadTest dbExpand dbToMenuH dbToRecordtypeH
|
||||
|
||||
# libs needed by PROD:
|
||||
#
|
||||
PROD_LIBS := Db Com
|
||||
|
||||
include $(TOP)/config/RULES.Host
|
||||
|
||||
# Extra rule since dbLexRoutines.c is included in dbYacc.c
|
||||
dbYacc$(OBJ): dbLex.c ../dbLexRoutines.c
|
||||
|
||||
clean::
|
||||
@$(RM) dbLex.c dbYacc.c
|
||||
|
||||
# EOF Makefile.Host for base/src/dbStatic
|
||||
@@ -1,29 +0,0 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/config/CONFIG_BASE
|
||||
|
||||
SRCS.c = \
|
||||
dbYacc.c \
|
||||
../dbPvdLib.c\
|
||||
../dbStaticRun.c\
|
||||
../dbStaticLib.c
|
||||
|
||||
OBJSdbLib = \
|
||||
dbYacc.o\
|
||||
dbPvdLib.o\
|
||||
dbStaticRun.o\
|
||||
dbStaticLib.o
|
||||
|
||||
PROD = dbStaticLib
|
||||
|
||||
include $(TOP)/config/RULES.Vx
|
||||
|
||||
# Extra rule since dbLexRoutines.c is included in dbYacc.c
|
||||
dbYacc.o: dbLex.c ../dbLexRoutines.c
|
||||
|
||||
clean::
|
||||
@$(RM) dbLex.c dbYacc.c
|
||||
|
||||
dbStaticLib: $(OBJSdbLib)
|
||||
$(RM) $@
|
||||
$(LINK.c) $@ $(OBJSdbLib) $(LDLIBS)
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
* .02 08-11-92 jba added new status DISABLE_ALARM, SIMM_ALARM
|
||||
* .03 05-11-94 jba added new status READ_ACCESS_ALARM, WRITE_ACCESS_ALARM
|
||||
* $Log$
|
||||
* Revision 1.3 1998/03/12 20:43:35 jhill
|
||||
* fixed string defs
|
||||
*
|
||||
* Revision 1.2 1996/06/19 19:59:31 jhill
|
||||
* added missing defines/enums, corrected defines
|
||||
*
|
||||
@@ -43,8 +46,8 @@
|
||||
#ifndef INCalarmh
|
||||
#define INCalarmh 1
|
||||
|
||||
#include <shareLib.h>
|
||||
#include <epicsTypes.h>
|
||||
#include "shareLib.h"
|
||||
#include "epicsTypes.h"
|
||||
|
||||
/* defines for the choice fields */
|
||||
/* ALARM SEVERITIES - NOTE: must match defs in choiceGbl.ascii GBL_ALARM_SEV */
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
#ifndef INCdbBaseh
|
||||
#define INCdbBaseh 1
|
||||
|
||||
#include <dbFldTypes.h>
|
||||
#include <ellLib.h>
|
||||
#include <dbDefs.h>
|
||||
#include "dbFldTypes.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbDefs.h"
|
||||
|
||||
typedef struct dbMenu {
|
||||
ELLNODE node;
|
||||
|
||||
@@ -19,9 +19,6 @@ of this distribution.
|
||||
|
||||
/*The routines in this module are serially reusable NOT reentrant*/
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -668,7 +665,6 @@ static void dbRecordtypeBody(void)
|
||||
pgphentry->userPvt = pdbRecordType;
|
||||
}
|
||||
ellAdd(&pdbbase->recordTypeList,&pdbRecordType->node);
|
||||
dbGetRecordtypeSizeOffset(pdbRecordType);
|
||||
}
|
||||
|
||||
static void dbDevice(char *recordtype,char *linktype,
|
||||
|
||||
@@ -9,10 +9,7 @@ This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -19,10 +19,6 @@ of this distribution.
|
||||
* .03 02-23-94 mrk dbPutString to DEV_CHOICE. Ok if no INP or OUT
|
||||
*/
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
@@ -30,6 +26,7 @@ of this distribution.
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cantProceed.h"
|
||||
#define DBFLDTYPES_GBLSOURCE
|
||||
#define GUIGROUPS_GBLSOURCE
|
||||
#define SPECIAL_GBLSOURCE
|
||||
@@ -527,29 +524,15 @@ void * epicsShareAPI dbCalloc(size_t nobj,size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p=calloc(nobj,size);
|
||||
if(p) return(p);
|
||||
printf("dbCalloc: Can't allocate memory\n");
|
||||
#ifdef vxWorks
|
||||
taskSuspend(0);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
return(NULL);
|
||||
p=callocMustSucceed(nobj,size,"dbCalloc");
|
||||
return(p);
|
||||
}
|
||||
void * epicsShareAPI dbMalloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p=malloc(size);
|
||||
if(p) return(p);
|
||||
printf("dbMalloc: Can't allocate memory\n");
|
||||
#ifdef vxWorks
|
||||
taskSuspend(0);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
return(NULL);
|
||||
p=mallocMustSucceed(size,"dbMalloc");
|
||||
return(p);
|
||||
}
|
||||
|
||||
#define INC_SIZE 256
|
||||
@@ -2096,7 +2079,7 @@ long epicsShareAPI dbPutString(DBENTRY *pdbentry,char *pstring)
|
||||
status = putPvLink(pdbentry,ppOpt|msOpt,pstr);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
/*break; is unnecessary*/
|
||||
case VME_IO: {
|
||||
char *end;
|
||||
|
||||
|
||||
@@ -314,11 +314,6 @@ long dbPutStringNum(DBENTRY *pdbentry,char *pstring)
|
||||
return(0);
|
||||
}
|
||||
|
||||
void dbGetRecordtypeSizeOffset(dbRecordType *pdbRecordType)
|
||||
{ /*For no run cant and dont need to set size and offset*/
|
||||
return;
|
||||
}
|
||||
|
||||
int epicsShareAPI dbGetMenuIndex(DBENTRY *pdbentry)
|
||||
{
|
||||
dbFldDes *pflddes = pdbentry->pflddes;
|
||||
|
||||
@@ -48,8 +48,6 @@ char *dbRecordName(DBENTRY *pdbentry);
|
||||
char *dbGetStringNum(DBENTRY *pdbentry);
|
||||
long dbPutStringNum(DBENTRY *pdbentry,char *pstring);
|
||||
|
||||
void dbGetRecordtypeSizeOffset(dbRecordType *pdbRecordType);
|
||||
|
||||
/* The following is for path */
|
||||
typedef struct dbPathNode {
|
||||
ELLNODE node;
|
||||
|
||||
@@ -15,20 +15,17 @@ of this distribution.
|
||||
* .01 06-12-95 mrk Initial
|
||||
*/
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <symLib.h>
|
||||
#include <sysSymTbl.h> /* for sysSymTbl*/
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "errMdef.h"
|
||||
#include "dbBase.h"
|
||||
#include "registryRecordType.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbDefs.h"
|
||||
@@ -648,24 +645,3 @@ long dbPutMenuIndex(DBENTRY *pdbentry,int index)
|
||||
}
|
||||
return (S_dbLib_badField);
|
||||
}
|
||||
|
||||
void dbGetRecordtypeSizeOffset(dbRecordType *pdbRecordType)
|
||||
{
|
||||
char name[60];
|
||||
SYM_TYPE type;
|
||||
STATUS vxstatus;
|
||||
long status;
|
||||
int (*sizeOffset)(dbRecordType *pdbRecordType);
|
||||
|
||||
strcpy(name,"_");
|
||||
strcat(name,pdbRecordType->name);
|
||||
strcat(name,"RecordSizeOffset");
|
||||
vxstatus = symFindByNameEPICS(sysSymTbl, name,
|
||||
(void *)&sizeOffset, &type);
|
||||
if (vxstatus != OK) {
|
||||
status = S_dbLib_noSizeOffset;
|
||||
errPrintf(status,__FILE__,__LINE__,"%s",name);
|
||||
return;
|
||||
}
|
||||
sizeOffset(pdbRecordType);
|
||||
}
|
||||
|
||||
@@ -112,10 +112,8 @@ int main(int argc,char **argv)
|
||||
fprintf(stderr,"Terminal error For input file %s\n",argv[1]);
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(outFile,"#include <vxWorks.h>\n");
|
||||
fprintf(outFile,"#include <semLib.h>\n");
|
||||
fprintf(outFile,"#include \"ellLib.h\"\n");
|
||||
fprintf(outFile,"#include \"fast_lock.h\"\n");
|
||||
fprintf(outFile,"#include \"osiSem.h\"\n");
|
||||
fprintf(outFile,"#include \"link.h\"\n");
|
||||
fprintf(outFile,"#include \"tsDefs.h\"\n");
|
||||
pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
* .06 01-10-96 lrd added ca_link structure fields
|
||||
*/
|
||||
|
||||
#include <dbDefs.h>
|
||||
#include "dbDefs.h"
|
||||
|
||||
#ifndef INClinkh
|
||||
#define INClinkh 1
|
||||
|
||||
Reference in New Issue
Block a user