diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 6415d0a7b..df024bc7b 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -15,6 +15,26 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.

Changes between 3.15.0.1 and 3.15.0.2

+

Full support for loadable support modules

+ +

Apparently later versions of Base 3.14 permitted support modules to be loaded +from a shared library at runtime without the IOC having been linked against that +shared library; the registerRecordDeviceDriver.pl program would accept a partial +DBD file containing just the entries needed for the library and generate the +appropriate registration code. In 3.15 however the registerRecordDeviceDriver.pl +program was replaced by one using the new DBD file parser, and in this a device +support entry would only be accepted after first loading the record type that it +depended on.

+ +

The parser has been modified to accept device entries without having seen the +record type first, although a warning is given when that happens. To remove the +warning the DBD file can provide a record type declaration instead (no fields +can be defined, so the braces must be empty), before the device() entry. The +result will generate the correct registration code for the device entry without +including anything for any merely declared record types. The generated code can +be linked into a shared library and loaded by an IOC at runtime using dlload. +

+

Parallel callback threads

The general purpose callback facility can run multiple parallel callback diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c index cf2406556..d1b3dc67e 100644 --- a/src/ioc/dbStatic/dbLexRoutines.c +++ b/src/ioc/dbStatic/dbLexRoutines.c @@ -62,6 +62,7 @@ static void dbMenuChoice(char *name,char *value); static void dbMenuBody(void); static void dbRecordtypeHead(char *name); +static void dbRecordtypeEmpty(void); static void dbRecordtypeBody(void); static void dbRecordtypeFieldHead(char *name,char *type); static void dbRecordtypeFieldItem(char *name,char *value); @@ -607,6 +608,23 @@ static void dbRecordtypeCdef(char *text) { return; } +static void dbRecordtypeEmpty(void) +{ + tempListNode *ptempListNode; + dbRecordType *pdbRecordType; + + if (duplicate) { + duplicate = FALSE; + return; + } + + ptempListNode = (tempListNode *)ellFirst(&tempList); + pdbRecordType = ptempListNode->item; + epicsPrintf("Declaration of recordtype(%s) preceeded full definition.\n", + pdbRecordType->name); + yyerrorAbort(NULL); +} + static void dbRecordtypeBody(void) { dbRecordType *pdbRecordType; diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y index b8cc9b4cf..858e666d3 100644 --- a/src/ioc/dbStatic/dbYacc.y +++ b/src/ioc/dbStatic/dbYacc.y @@ -100,7 +100,12 @@ recordtype_head: '(' tokenSTRING ')' dbRecordtypeHead($2); dbmfFree($2); }; -recordtype_body: '{' recordtype_field_list '}' +recordtype_body: '{' '}' +{ + if(dbStaticDebug>2) printf("empty recordtype_body\n"); + dbRecordtypeEmpty(); +} + | '{' recordtype_field_list '}' { if(dbStaticDebug>2) printf("recordtype_body\n"); dbRecordtypeBody(); @@ -215,14 +220,14 @@ record_head: '(' tokenSTRING ',' tokenSTRING ')' dbRecordHead($2,$4,0); dbmfFree($2); dbmfFree($4); }; -record_body: /*Null*/ +record_body: /* empty */ { if(dbStaticDebug>2) printf("null record_body\n"); dbRecordBody(); } | '{' '}' { - if(dbStaticDebug>2) printf("record_body - no fields\n"); + if(dbStaticDebug>2) printf("empty record_body\n"); dbRecordBody(); } | '{' record_field_list '}' diff --git a/src/libCom/osi/os/Linux/osdFindSymbol.c b/src/libCom/osi/os/RTEMS/osdFindSymbol.c similarity index 64% rename from src/libCom/osi/os/Linux/osdFindSymbol.c rename to src/libCom/osi/os/RTEMS/osdFindSymbol.c index 967c220cd..9e947f95c 100644 --- a/src/libCom/osi/os/Linux/osdFindSymbol.c +++ b/src/libCom/osi/os/RTEMS/osdFindSymbol.c @@ -1,27 +1,31 @@ /*************************************************************************\ * Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* osi/os/default/epicsFindSymbol.c */ +/* osi/os/RTEMS/osdFindSymbol.c */ -#include +/* GESYS could support this, but must use compile-time detection + * as the code must build for non-GESYS systems as well. + */ #define epicsExportSharedSymbols #include "epicsFindSymbol.h" epicsShareFunc void * epicsLoadLibrary(const char *name) { - return dlopen(name, RTLD_LAZY | RTLD_GLOBAL); + return 0; } epicsShareFunc const char *epicsLoadError(void) { - return dlerror(); + return "epicsLoadLibrary not implemented"; } epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) { - return dlsym(0, name); + return 0; } diff --git a/src/libCom/osi/os/WIN32/osdFindSymbol.c b/src/libCom/osi/os/WIN32/osdFindSymbol.c index ed2b79c95..6de3c428e 100644 --- a/src/libCom/osi/os/WIN32/osdFindSymbol.c +++ b/src/libCom/osi/os/WIN32/osdFindSymbol.c @@ -3,7 +3,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* osi/os/WIN32/epicsFindSymbol.c */ +/* osi/os/WIN32/osdFindSymbol.c */ #include diff --git a/src/libCom/osi/os/default/osdFindSymbol.c b/src/libCom/osi/os/default/osdFindSymbol.c index 99ca2832d..9d9a8878c 100644 --- a/src/libCom/osi/os/default/osdFindSymbol.c +++ b/src/libCom/osi/os/default/osdFindSymbol.c @@ -6,16 +6,22 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* osi/os/default/epicsFindSymbol.c */ +/* osi/os/default/osdFindSymbol.c */ #define epicsExportSharedSymbols #include "epicsFindSymbol.h" epicsShareFunc void * epicsLoadLibrary(const char *name) -{ return 0; } +{ + return 0; +} epicsShareFunc const char *epicsLoadError(void) -{ return "epicsLoadLibrary not implemented"; } +{ + return "epicsLoadLibrary not implemented"; +} epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) -{ return 0;} +{ + return 0; +} diff --git a/src/libCom/osi/os/Darwin/osdFindSymbol.c b/src/libCom/osi/os/posix/osdFindSymbol.c similarity index 95% rename from src/libCom/osi/os/Darwin/osdFindSymbol.c rename to src/libCom/osi/os/posix/osdFindSymbol.c index 967c220cd..acfc405e5 100644 --- a/src/libCom/osi/os/Darwin/osdFindSymbol.c +++ b/src/libCom/osi/os/posix/osdFindSymbol.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* osi/os/default/epicsFindSymbol.c */ +/* osi/os/posix/osdFindSymbol.c */ #include diff --git a/src/libCom/osi/os/solaris/osdFindSymbol.c b/src/libCom/osi/os/solaris/osdFindSymbol.c deleted file mode 100644 index 967c220cd..000000000 --- a/src/libCom/osi/os/solaris/osdFindSymbol.c +++ /dev/null @@ -1,27 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ -/* osi/os/default/epicsFindSymbol.c */ - -#include - -#define epicsExportSharedSymbols -#include "epicsFindSymbol.h" - -epicsShareFunc void * epicsLoadLibrary(const char *name) -{ - return dlopen(name, RTLD_LAZY | RTLD_GLOBAL); -} - -epicsShareFunc const char *epicsLoadError(void) -{ - return dlerror(); -} - -epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) -{ - return dlsym(0, name); -} diff --git a/src/libCom/osi/os/vxWorks/osdFindSymbol.c b/src/libCom/osi/os/vxWorks/osdFindSymbol.c index d9c9d1161..785327e8b 100644 --- a/src/libCom/osi/os/vxWorks/osdFindSymbol.c +++ b/src/libCom/osi/os/vxWorks/osdFindSymbol.c @@ -6,7 +6,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* osi/os/vxWorks/osiFindSymbol */ +/* osi/os/vxWorks/osdFindSymbol */ /* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */ #define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h> diff --git a/src/tools/DBD/Parser.pm b/src/tools/DBD/Parser.pm index 8cace9c17..b8cc82783 100644 --- a/src/tools/DBD/Parser.pm +++ b/src/tools/DBD/Parser.pm @@ -59,9 +59,12 @@ sub ParseDBD { \s* $RXstr \s* , \s*$RXstr \s* \)/oxgc) { print "Device: $1, $2, $3, $4\n" if $debug; my $rtyp = $dbd->recordtype($1); - dieContext("Unknown record type '$1'") - unless defined $rtyp; - $rtyp->add_device(DBD::Device->new($2, $3, $4)); + if (!defined $rtyp) { + $rtyp = DBD::Recordtype->new($1); + warn "Device using undefined record type '$1', place-holder created\n"; + $dbd->add($rtyp); + } + $rtyp->add_device(DBD::Device->new($2, $3, $4)); } else { last unless m/\G (.*) $/moxgc; dieContext("Syntax error in '$1'"); diff --git a/src/tools/DBD/Recordtype.pm b/src/tools/DBD/Recordtype.pm index f730777a3..d0d76a5a0 100644 --- a/src/tools/DBD/Recordtype.pm +++ b/src/tools/DBD/Recordtype.pm @@ -83,7 +83,9 @@ sub toCdefs { } sub equals { - my ($a, $b) = @_; + my ($new, $known) = @_; + return 0 if ! $known->fields; + return 1 if ! $new->fields; dieContext("Duplicate definition of record type '$a->{NAME}'"); } diff --git a/src/tools/registerRecordDeviceDriver.pl b/src/tools/registerRecordDeviceDriver.pl index 91a22c903..368d7acea 100644 --- a/src/tools/registerRecordDeviceDriver.pl +++ b/src/tools/registerRecordDeviceDriver.pl @@ -20,10 +20,10 @@ use EPICS::Path; use EPICS::Getopts; use Text::Wrap; -our ($opt_D, @opt_I, $opt_o); +our ($opt_D, @opt_I, $opt_o, $opt_l); -getopts('Do:I@') or - die "Usage: registerRecordDeviceDriver [-D] [-o out.c] [-I dir] in.dbd subname [TOP]"; +getopts('Dlo:I@') or + die "Usage: registerRecordDeviceDriver [-D] [-l] [-o out.c] [-I dir] in.dbd subname [TOP]"; my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32? @@ -69,37 +69,52 @@ print $out (<< "END"); #include "iocshRegisterCommon.h" #include "registryCommon.h" +END + +print $out (<< "END") if $opt_l; +#define epicsExportSharedSymbols +#include "shareLib.h" + +END + +print $out (<< "END"); extern "C" { END my %rectypes = %{$dbd->recordtypes}; +my @rtypnames; my @dsets; if (%rectypes) { - my @rtypnames = sort keys %rectypes; + my @allrtypnames = sort keys %rectypes; + # Record types with no fields defined are declarations, + # for building shared libraries containing device support. + @rtypnames = grep { scalar $rectypes{$_}->fields } @allrtypnames; - # Declare the record support entry tables - print $out wrap('epicsShareExtern rset ', ' ', - join(', ', map {"*pvar_rset_${_}RSET"} @rtypnames)), ";\n\n"; + if (@rtypnames) { + # Declare the record support entry tables + print $out wrap('epicsShareExtern rset ', ' ', + join(', ', map {"*pvar_rset_${_}RSET"} @rtypnames)), ";\n\n"; - # Declare the RecordSizeOffset functions - print $out "typedef int (*rso_func)(dbRecordType *pdbRecordType);\n"; - print $out wrap('epicsShareExtern rso_func ', ' ', - join(', ', map {"pvar_func_${_}RecordSizeOffset"} @rtypnames)), ";\n\n"; + # Declare the RecordSizeOffset functions + print $out "typedef int (*rso_func)(dbRecordType *pdbRecordType);\n"; + print $out wrap('epicsShareExtern rso_func ', ' ', + join(', ', map {"pvar_func_${_}RecordSizeOffset"} @rtypnames)), ";\n\n"; - # List of record type names - print $out "static const char * const recordTypeNames[] = {\n"; - print $out wrap(' ', ' ', join(', ', map {"\"$_\""} @rtypnames)); - print $out "\n};\n\n"; + # List of record type names + print $out "static const char * const recordTypeNames[] = {\n"; + print $out wrap(' ', ' ', join(', ', map {"\"$_\""} @rtypnames)); + print $out "\n};\n\n"; - # List of pointers to each RSET and RecordSizeOffset function - print $out "static const recordTypeLocation rtl[] = {\n"; - print $out join(",\n", map { - " {pvar_rset_${_}RSET, pvar_func_${_}RecordSizeOffset}" - } @rtypnames); - print $out "\n};\n\n"; + # List of pointers to each RSET and RecordSizeOffset function + print $out "static const recordTypeLocation rtl[] = {\n"; + print $out join(",\n", map { + " {pvar_rset_${_}RSET, pvar_func_${_}RecordSizeOffset}" + } @rtypnames); + print $out "\n};\n\n"; + } - for my $rtype (@rtypnames) { + for my $rtype (@allrtypnames) { my @devices = $rectypes{$rtype}->devices; for my $dtype (@devices) { my $dset = $dtype->name; @@ -206,7 +221,7 @@ print $out (<< 'END'); END -print $out (<< 'END') if %rectypes; +print $out (<< 'END') if %rectypes && @rtypnames; registerRecordTypes(pbase, NELEMENTS(rtl), recordTypeNames, rtl); END