Merged the loadable-support branch

This commit is contained in:
Andrew Johnson
2014-10-02 16:53:15 -05:00
12 changed files with 115 additions and 69 deletions

View File

@@ -15,6 +15,26 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.</p>
<h2 align="center">Changes between 3.15.0.1 and 3.15.0.2</h2>
<!-- Insert new items immediately below here ... -->
<h3>Full support for loadable support modules</h3>
<p>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.</p>
<p>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.
</p>
<h3>Parallel callback threads</h3>
<p>The general purpose callback facility can run multiple parallel callback

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <dlfcn.h>
#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);
}

View File

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

View File

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

View File

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

View File

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