home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1997 January
/
Chip_1997-01_cd.bin
/
ms95
/
disk19
/
dir01
/
f014050.re_
/
f014050.re
Wrap
Text File
|
1996-04-02
|
49KB
|
1,043 lines
Feature:
Dynamic Link Modules
Description:
Dynamic Link Modules - Introduction
Following are definitions of some of the terms and phrases used in the
description of Dynamic Link Modules:
built-ins - variables and functions that are actually part of
MicroStation, but are accessible to MDL applications. They are also
available to Dynamic Link Modules.
Dynamic Link Modules (DLM) - modules that can be loaded and linked
by MicroStation at runtime. These modules are compiled into native
machine code. Dynamic Link Modules are created using the host
operating system's tools such as the compiler and linker. The MDL
tools are not used to create a Dynamic Link Module.
Dynamic Link Specification (DLS) - used to specify what symbols
can be resolved from a specific Dynamic Link Module. A Dynamic Link
Specification source file is compiled using the program "dlmspec"
(supplied by Bentley Systems) to create a Dynamic Link
Specification object file. A Dynamic Link Specification object file
is used when linking an MDL application to tell mlink what symbols
will be resolved from the Dynamic Link Module.
native code - code created by using standard compilers and
linkers. The keyword nativeCode in a declaration tells the MDL
compiler that the function or variable being declared is part of
MicroStation or a DLM. The function or variable being declared is
not part of the MDL application but is accessible from the MDL
application.
pseudo-code instructions - instructions generated by the MDL
compiler and understood by MicroStation's MDL interpreter.
task ID - the name used for an MDL or MicroCSL application. This
name appears in MicroStation input queue elements. It also is used
in MicroStation commands that refer to MDL applications. For
example, in the command "MDL UNLOAD QDIM", QDIM is the task ID. It
is also displayed in the MDL Applications dialog box.
resources - in this document, resource does not refer to the kind
of resources that are managed by the MicroStation Resource Manager.
It refers to anything a DLM or MicroStation may allocate and
release for an MDL application. Examples are memory and file
handles.
user hooks - MDL functions called by native code functions. Both
MicroStation and DLM's can call MDL user hooks.
Dynamic linking addresses a number of developer concerns. These are:
performance of MDL.
shared libraries for their MDL applications to use. Developers
often have multiple applications with common code.
access to object-code libraries (with some limitations).
ability to use the MDL builtin functions from native machine code.
The main concerns with Dynamic Link Modules:
printf may be the best debugging tool. The Clipper is the only
platform with source level debugging for DLM's. On the PC, the
PharLap debugger takes the symbols from the DLM.
The features of dynamic linking are not guaranteed to be available
on all platforms. In fact, it still is not known if it will be
available on the Macintosh.
Applications share the stack with MicroStation. On some platforms
including the PC, the applications are limited by the size of
MicroStation's stack. This is not a problem on any of the Unix
platforms.
DLM's may be restricted to position independent code. When this is
necessary, it does not seem to create any problems. This is
achieved through compiler flags.
There might be problems when different Dynamic Link Modules define
symbols of the same name. On both the HP and Sparc, if 2 DLM's define
the global data with the same name, then both applications share the
same data. DLM's generally should be coded with as few globals as
possible, and all of the globals named so that the names are likely
to be unique across applications.
In general, it is dangerous to have a DLM that needs to be linked with
any system libraries. When linking with a system library, it is very
difficult to link in the desired modules from the library without
bringing in extra modules. For example, the link step may bring in a
new copy of heap management but may not have any of the heap
management data structures initialized.
There are 2 known limitiations with the Sparc dynamic linking. First, all
data must be initialized because the SunOS utility ld.so does not correctly
initialize the BSS segment. Second, if a function in a DLM tries to call
another function in same DLM but from a different source module, and
MicroStation has a function with the same name as the called function, then
MicroStation's function is called instead of the one in the same DLM.
When Should a DLM Be Used
A DLM should not be the key component of an application's architecture. If
the bulk of an application must be in native code, the application should
use the external program interface.
A DLM is ideal when an MDL application or group of applications need
functions that must be compiled in native code either due to performance
considerations, or because the functions must access some system features
that are not available through MDL. These functions can be packaged
together in a DLM to be used by these applications.
Use of System Libraries
Whenver possible, use MicroStation's built-in functions instead of
functions from system libraries. The set of MicroStation's built-in
functions includes nearly the entire ANSI C library.
Using system libraries can sometimes become quite complicated. It
can be very difficult to figure out how to build the DLM. It increases
the risks that it will be more difficult to move the application to
MicroStation upgrades, operating system upgrades, or other operating
systems. It also increases the risk of problems resulting from
interaction with other applications.
Examples of functions that must not be resolved from system libraries
are malloc and fopen. If a DLM brings in its own copy of malloc, then
the MicroStation process will have 2 copies of malloc. Each copy of
malloc will operate as if it has exclusive control of controlling
MicroStation's heap. This generally works for a while, and then
eventually leads to heap problems and a crash. This problem occurs
even if malloc is resolved from the C shared library. When malloc is
resolved from the C shared library, it also causes the linker to bind in
the static data structures used in tracking heap management. Having this
data structure duplicated leads to the heap management problems.
Typically, it should be safe to use library functions that that do not
save any state information in global data structures. fopen and malloc
are dangerous because they save state information in global data structures.
fopen saves state information in the iob. malloc saves state information
in the heap management data structures. kill is okay because is does
not save state information. It just sends a signal to another process
and returns.
It is okay to use the shared libraries that MicroStation uses. The
XWindows versions of MicroStation use the X shared libraries and the
C shared libraries. The Environ V version of MicroStation uses the
libtools2 shared library and the C shared library. Howver, on the
Intergraph workstation, the DLM should not use functions that require
global data structures.
On the Intergraph workstation, MicroStation version 4.4 generates an
error messages and refuses to load a DLM if the DLM redefines malloc,
calloc, free, fopen, brk, sbrk, or iob.
Dynamic Link Modules - Changes to MDL Source
The MDL compiler generates special instructions for accessing
functions and variables that are not part of the MDL program.
Therefore, it is necessary to identify for the compiler the symbols
that refer to functions and variables that are not in the MDL
application. To indicate that these symbols refer to code or data
implemented in native code rather than MDL, declare them using a
storage class of nativeCode. The following declarations tell the MDL
compiler that "exampleFunc" is a function that was compiled to machine
code, and that "exampleVar" is a variable defined in a native module.
nativeCode int exampleFunc (int firstParam);
nativeCode long exampleVar;
When the MDL compiler compiles code that uses a function pointer, it
must know whether that pointer points to an MDL function or a
nativeCode function. By default, function pointers in MDL refer to
MDL functions. A typedef or variable can be designated as a pointer
to a native-code function through use of the pointerToNative pragma. The
following lines would be used to create a typedef for pointing to a
native code function.
typedef int (*FuncP)();
#pragma pointerToNative funcP
The syntax for the pointerToNative pragma is:
#pragma pointerToNative <object-name> [,] ....
where object-name refers to a variable or typedef name. The
pointerToNative pragma accepts a comma-separated list of object-names.
Each object-name must be a typedef name or variable name. The object
must have type pointer-to-function.
Dynamic Link Modules - Access to MicroStation's Built-ins
On some platforms, DLM source files must include the file "dloadlib.h"
to be able to access built-in functions using the same names MDL
programs use. Dloadlib.h contains define statements that cause the C
preprocessor to replace references to MDL built-ins with references to
the internal names for the built-in functions and variables.
Dloadlib.h is platform specific. On both the Intergraph platform and
PC's, it does not do anything. Because of the way dynamic linking is
implemented on these platforms, it is not necessary to translate any
of the names. The versions for the HP and SPARC contain a lot of
defines because there are a lot names to translate.
If a source file includes dloadlib.h, then it should be possible to
use that source file unchanged on all platforms both as MDL source and
as DLM source. All of the differences should be handled by dloadlib.h.
Dynamic Link Modules - Linking an MDL Program with a DLM
The MDL linker "mlink" must know how to resolve the symbols for the
DLM. It must know what symbols can be resolved at runtime. Since the
DLM itself cannot be linked with the MDL program, a Dynamic Link
Specification (DLS) object file is used. The DLS object file specifies
the name of the dynamic link module, the list of symbols to be
resolved from the dynamic link module, and the version number of the
library. All of this information can be linked with the MDL program so
that MicroStation can use it at runtime to dynamically load and link
the DLM.
The syntax for Dynamic Link Specification files is described in the
section "Dynamic Link Modules - Dynamic Link Specification Source
Files"..
"mlink" treats DLS object files like libraries. It does not make the
DLS object file part of the program unless the DLS object file
resolves symbols required by the mdl object files. Since it is treated
like a library, the DLS object file must appear in the link step after
any MDL object files that use functions or variables from the
corresponding DLM.
The Dynamic Link Specification object file must be specified for every
link step that may resolve symbols from that file. To simplify this,
mlink now uses the environment variable MLINK_STDLIB. MLINK_STDLIB
specifies a list of object files to be included in a link step. This
list may be up to 400 characters. The entries in the list are blank
separated. After processing the command line, mlink gets the value of
MLINK_STDLIB. If the environment variable MLINK_STDLIB is defined,
mlink interprets it as a list of files. This list is appended to the
list of input files specified in the command line.
Dynamic Link Modules - Runtime Concerns
MicroStation's DLM's are modeled after standard dynamically linked
shared libraries. MicroStation does not create a process (does not
allocate a process descriptor or MDL descriptor) for a DLM. A DLM is
primarily a set of functions that can be called by MDL programs. A DLM
is loaded only if it is required by an MDL program. The DLM is
required by an MDL program if "mlink" resolved references for the
program from a corresponding Dynamic Link Specification object file.
Generally, a DLM executes only when a function in the DLM is called by
an MDL program or if MicroStation calls one of the DLM's hook
functions.
If a DLM is called by an MDL program, then that MDL program is the
current process while the DLM executes. If the DLM calls any functions
that allocate resources that must belong to a process, then the
resources will belong to the MDL program.
It is difficult to predict what the current process will be when
MicroStation calls a DLM hook function. For example, a DLM can have a
hook that is called when an MDL program is unloaded, When MicroStation
calls this hook, the current process is random. It may be the MDL
program affected by what is going on at the time, or it may be
MicroStation. If it is important for the DLM to know what MDL program
is affected, then a pointer to the MDL descriptor is provided as a
parameter.
MicroStation never loads more than 1 copy of a DLM. If there are
multiple requests to load the DLM, then MicroStation keeps track of
the number of requests. Each time there is a request to unload the
DLM, MicroStation decrements the counter of opens. If the counter goes
to 0 then the DLM is physically unloaded.
Dynamic Link Modules - Function Pointers as Parameters to
MicroStation's Built-in Functions
DLM function pointers and MDL function pointers cannot be used
interchangeably. Using an MDL function pointer where a real function
pointer is expected would cause a fault. Also, using a real function
pointer where an MDL function pointer is expected would cause a fault.
There are a lot of MDL functions for establishing user hooks. These
functions generally have a form similar to mdlSystem_setFunction
(<function-type>, <function-pointer>). The <function-pointer> must be
an offset into the current MDL application. It cannot be a pointer
into the DLM. Therefore, a DLM can call one of these functions to set
up a hook for an MDL application, but it cannot use these to set up a
hook for itself.
In MicroStation's FDF files, all function parameters that are MDL
function pointers are declared as type MdlFunctionP. MdlFunctionP is
declared in mdl.h as:
#if defined (mdl)
typedef int (*MdlFunctionP)();
#else
typedef unsigned long MdlFunctionP;
#endif
If a source file includes the FDF files, then it should be impossible
to pass real function pointers where MDL function offsets are
expected. Declarations such as the one for mdlSystem_setFunction
should cause the compiler to catch all invalid uses of the these
functions.
void mdlSystem_setFunction
(
int type,
MdlFunctionP function
);
Dynamic Link Modules - Identifying MDL Applications
It may be important for some DLM's to keep track of certain MDL
applications, particularly if the DLM is used by more than 1 MDL
application, and the DLM allocates and frees resources for these
applications. The DLM should be able to detect when the application is
removed. It should then free any of the application's resources that
the application failed to free. MicroStation provides built-in
functions to let a DLM track an MDL application. MicroStation can
notify a DLM whenever an MDL application is unloaded.
Internally, MicroStation manages data structures called MDL
descriptors to track the status of MDL applications. The format of the
MDL descriptor is not published. However, the pointers to the MDL
descriptors are still very important. Internally, most of the
functions used to manage MDL functions require a pointer to an MDL
descriptor as a parameter. A DLM can call the function
mdlSystem_getCurrMdlDesc to get a pointer to the MDL descriptor of the
MDL application that called it. The task ID associated with an MDL
descriptor can be determined with the function "mdlSystem_getMdlTaskID
(mdlDescP)". The MDL descriptor for a task can be determined with
"mdlSystem_findMdlDesc (taskIdP)" where taskIdP points to the
application's task ID. This task ID is not case sensitive.
The MDL descriptor is essentially the internal name, and the task ID
is the external name. The task ID is also used in MicroStation input
queue elements.
A DLM can have an unload hook that is called whenever an MDL
application is unloaded. It can use this hook to free any resources
allocated by the DLM for the MDL application.
See the section "Dynamic Link Modules - Function Call Specifications"
for more information on these functions.
Dynamic Link Modules - Calling Custom User Hooks
This section describes how native code can call MDL functions. Many
names are used for this mechanism. Some of the names are "call backs",
"user hooks", "asynchronous functions", and "filters". The term "user
hooks" is used in this document.
The mechanism described here works regardless of whether or not the
native code was called by an MDL function. The mechanism works even if
the native code is called by one MDL application and calls a function
in another MDL application.
A DLM cannot directly call functions in MDL programs. It must use
dlmSystem_callMdlFunction to call these functions. This does not
mean that they cannot call MDL built-in functions. A DLM must use
use dlmSystem_callMdlFunction to call functions in MDL programs, but
can call built-in functions directly.
To call an MDL function, the native code must know the offset for that
function, and the address of the MDL descriptor for the application
that contains that function. An MDL function pointer is not an
absolute addresses. It is an offset from the start of the
application's code segment. The MDL linker forces the offset to be 8
or greater, so 0 can be used to represent a NULL MDL function pointer.
MicroStation needs a pointer to the MDL descriptor to determine the
start of the code segment so that it can figure out the absolute
address of the function.
When MicroStation calls an MDL function, its saves the current value
of currMdlDesc, and sets it to the valued passed into
dlmSystem_callMdlFunction. When dlmSystem_callMdlFunction returns,
MicroStation restores currMdlDesc.
See the section "Dynamic Link Specifications - New Built-in Functions"
for more information on dlmSystem_callMdlFunction.
Dynamic Link Modules - Determining When an MDL Program is Unloaded
It is often important to know when an MDL application is being
unloaded. For example, if a DLM calls an MDL application's user hook
after the application has been unloaded, then something random will
happen. Also, if the DLM is allocating and tracking resources for an
MDL application, then it must know to free those resources when the
application is unloaded.
The DLM can use an unload hook to learn when an MDL application is
unloaded. To install an unload hook, the DLM must call
"dlmSystem_setFunction (DLM_SYSTEM_MDL_UNLOAD, <dlmID>,
<unloadFunctionP>)". When an MDL application is unloaded, MicroStation
will call the unload hook passing the application's MDL descriptor as
a parameter.
Each DLM may have an unload hook, but a given DLM may have only 1
hook. To remove an unload hook, call "dlmSystem_setFunction
(DLM_SYSTEM_MDL_UNLOAD, <dlmID>, NULL)".See the description of
userHook_mdlUnload for more information on this user hook.
Dynamic Link Modules - Application-Specific Resources versus System
Resources
There are a number of functions that allocate resources for an MDL
program. These resources then belong to the MDL program. Examples are
dlmSystem_mdlMalloc and dlmSystem_mdlFopen. These handle malloc and
fopen calls from MDL programs.
Files opened with dlmSystem_mdlFopen must always be closed with
dlmSystem_mdlFclose. Otherwise, the FILE pointer returned by
dlmSystem_mdlFopen may be used just like a FILE pointer returned by
fopen. In fact, dlmSystem_mdlFopen returns the FILE pointer returned
to it by fopen.
Memory allocated by dlmSystem_mdlMalloc, dlmSystem_mdlCalloc, or
dlmSystem_mdlRealloc must be freed by dlmSystem_mdlFree. Memory
allocated by malloc must be freed by calling free. An MDL application
cannot free memory that a builtin or DLM function allocated by calling
malloc directly. Memory allocated by calling dlmSystem_mdlMalloc is
automatically freed by MicroStation when the MDL application is
unloaded.
Dynamic Link Modules - Dynamic Link Specification Source Files
This section describes the syntax used for Dynamic Link Specification
source files. The program dlmspec is used to compile a Dynamic Link
Specification source file producing a Dynamic Link Specification
object file. The object file is used at link time to specify
information on symbols that are to be resolved at runtime. Normal MDL
object files (.mo files) that need to have symbols resolved from a
given Dynamic Link Specification object file must appear in mlink's
command line prior to the Dynamic Link Specification file.
The statements in a Dynamic Link Specification file can be categorized
as preprocessor directives and commands. Comments are also supported.
Comments are bracketed with /* and */.
All preprocessor directives contain "#" at the start of a line.
"#include" can be used to include other source files. "if", "else",
"elif", "endif", "ifdef", and "endif" can be used for conditional
compilation. "define" can be used to define values used for
conditional compilation. It cannot be used to define macros. The
Dynamic Link Specification compiler "dlmspec" defines standard
constants that can be used for conditional compilation. The defines
that are built in for the appropriate platforms are msdos, pm386,
IP32, clipper, unix, sparc, hp700, macintosh, vax, BIG_ENDIAN,
EnvironV, and XWindow.
The commands all begin with "%". The commands are Version, Functions,
EndFunctions, Variables, EndVariables, ModuleName, and End.
%Version is followed by a version number. This version number is saved
in the Dynamic Link Specification object file. It is also saved with
the application at link time. At load time, this version number is
provided to the DLM's initialization function.
%Functions tells dlmspec to start processing the subsequent symbols as
function names. It is used to specify the list of functions that can
be resolved at runtime. %EndFunctions is used to signal the end of the
list. Any number of pairs of %Functions %EndFunctions can be used, but
they cannot be embedded.
%Variables tells dlmspec to start processing the subsequent symbols as
variable names. It is used to specify the list of variables that can
be resolved at runtime. %EndVariables is used to signal the end of the
list. Any number of pairs of %Variables %EndVariables can be used.
%ModuleName is followed by the name of a file. For DLM's, this is used
at runtime to determine the name of the file containing the DLM. The
file name suffix usually is not specified. It is system-specific. It
is provided by MicroStation at runtime. The defaults are ".out"
(Clipper), ".rex" (PC), ".so" (Sparc), and ".sl" (HP700).
An application should not use more than one DLM source file to
describe one DLM.
The final command in a Dynamic Link Module specification source file
must be %End.
6. Additional Include Files
The following files are provided:
dloadlib.h - this file contains #defines that map the MDL names
into the real MicroStation names if the MicroStation names are
needed to load the DLM. This file is system specific. On platforms
where the operating system resolves dynamic links, it has a lot of
entries. On systems such as the PC and Intergraph platform where
MicroStation resolves the dynamic links, MicroStation maps the
names at runtime so this file is not needed. On these platforms, a
dummy dloadlib.h is provided.
dlmfuncs.h - this contains declarations and definitions that are
only used by DLM's.
fdf files for all of the MDL builtin's that are not in the
standard C library. Most of these built-ins are available to both
DLM's and MDL programs.. Both MDL source and DLM source can use the
FDF files. The files are provided in the mdl/include directory
along with all of the MDL header files. The file dlmsys.fdf
declares functions that are available only to DLM's. The other FDF
files declare functions that are available to both DLM's and MDL
programs.
Dynamic Link Modules - Example
The mdl/examples/dlink directory contains an example that illustrates
most of the important concepts needed to implement a DLM. This example
implements the Unix file io functions read, write, open, close, etc.
To compile and link this example, just run "bmake -I$MS/mdl/include/
fileio". Doing this will build the application including both the MDL
program and the DLM. Then load the MDL applications testio1 or testio2.
MicroStation will see that the application needs the DLM and will
automatically load it.
The concepts illustrated in the example are:
Dynamic Link Specification source file.
Sample make file.
Associating resources - file handles in this case - with a
specific MDL application.
Using 2 names for a given function - the name used within the DLM
and the name used for access from an MDL program.
Support for MDL user hooks called from the DLM.
DLM hook functions.
Use of an initialization function.
Use of the error reporting function.
DLM Example - Dynamic Link Specification Source File
The Dynamic Link Specification source file is fileio.dls. It has
sections specifying the version number, module name, and function
names. The %Version command specifies a number that is stored with the
Dynamic Link Specification object file. It is also stored with any MDL
application created with this object file. When the DLM is loaded into
memory, MicroStation calls the DLM's initialization function. The
version number is passed as one of the parameters. In this example,
the initialization function initialize in filemain.c verifies that the
version number is less than 0x500. If it 0x500 or greater, then it
rejects the load request and displays a message saying that the
versions are incompatible.
The %ModuleName command specifies the name of the file that contains
the DLM. In this example it provides the name "fileio" to specify that
the DLM is in the file "fileio.out" (Clipper), "fileio.rex" (PC),
"fileio.so" (Sparc), or "fileio.sl" (HP700).
The %Functions section specifies what functions can be accessed from
an MDL program that is linked with this DLM. For each function, if
only 1 function name is given then that name is used both within the
MDL program and within the DLM. If a specification also contains a
name in parentheses, then the name preceding the parentheses is used
by the MDL program and the name in the parentheses is the name used by
the DLM. Consider the case "open (fileio_open)". When the MDL program
calls the function open, it is calling the DLM's function fileio_open.
This example contains an empty Variables section. This section would
be used for listing the variables that can be accessed from the MDL
application. The format is the same as for functions.
DLM Example - Managing Application Resources
When MicroStation allocates resources for an MDL task, it associates
those resources with that MDL task. If the MDL task is unloaded, then
MicroStation must free those resources. Since a DLM should appear to
be part of MDL, it must behave the same way. When an MDL application
is unloaded, a DLM must also release all resources it allocated for
that application.
In this example, file handles are allocated by open, create, and dup.
Therefore, the DLM must intercept all calls to these functions and
record what MDL application called the function.
The first step in the procedure is to establish different internal and
external names for these functions. This is done in the Dynamic Link
Specification file. Note that the specification for open is "open
(fileio_open)". This specifies that the name "open" can be used in an
MDL program. When the MDL program calls open, MDL will call the DLM's
function fileio_open.
The function fileio_open must associate the current MDL application
and the file handle returned by the real open. To get an identifier
for the MDL application, it calls mdlSystem_getCurrMdlDesc. Then it
finds a free entry in the array fileList. It that entry, it records
both the file handle and the MDL descriptor.
The DLM also intercepts calls to close. When the MDL application calls
close, the DLM's function fileio_close intercepts the call. It clears
the data structure where it had established that the handle was
associated with this MDL application.
The final step in controlling the file handles is to guarantee that
when the MDL application is unloaded, all of its open files will be
closed. To do this, the DLM sets up an MDL unload function
mdlUnloadHook to be called whenever an MDL application is unloaded.
MicroStation passes a pointer to the MDL descriptor when it calls the
unload hooks. The DLM uses this pointer to determine what files are
owned by the MDL application that is being unloaded. It closes all of
these files.
DLM Example - Support of MDL User Hooks
This application supports a user hook to be called whenever an MDL
application opens, creates, or dups a file.
MDL applications set up the user hook by calling fileio_setFunction.
This function records the offset of the function and the current MDL
descriptor. Whenever an MDL application opens, creates, or dups a file
the DLM calls all of the hooks using the function
dlmSystem_callMdlFunction. The first 2 parameters for this function
are a pointer to an MDL descriptor and the offset to the MDL function.
The remaining parameters are variable. These parameters are passed to
the MDL function.
DLM Example - DLM Hook Functions
The DLM "fileio" sets up a hook function to be called whenever an MDL
application is unloaded. It does this by calling
dlmSystem_setFunction. Notice that this function is similar to the
mdlSystem_setFunction except that the second parameter identifies the
DLM. When an MDL application sets a user hook it does not have to
identify itself because MicroStation always knows what MDL application
is active. However, MicroStation does not have any concept of active
DLM. Therefore, a DLM must identify itself it the
dlmSystem_setFunction call. When MicroStation calls the DLM's
initialization function, it provides the DLM's identifier as one of
the parameters. The DLM uses this identifier as the second argument in
calls to dlmSystem_setFunction.
DLM Example - Use of Initialization Function
The DLM fileio contains an initialization function. This function is
called immediately after the DLM is loaded. Typically, this is used to
verify that the versions are compatible and to set up any hook
functions that are required.
The initialization function must always be called initialize.
If the initialization function returns anything other than SUCCESS
then the load fails and the MDL application is unloaded.
See the section "Dynamic Link Modules - New Built-in Functions" for
more information on initialize.
DLM Example - Use of Error Reporting Function
Typically, when a load fails a lot of error messages are required to
completely explain what happened. The message fields in the command
window are not sufficient for this. Therefore, load errors are
reported with the function dlmSystem_displayError. The format for this
is the same as for printf, except that the messages should not have a
newline. The function dlmSystem_displayError appends a newline to
every message. The dlmSystem_displayError function is also available
to DLM's.
DLM Example - Platform Specific Notes
At the time this document was written, the example had been tested on
a SPARCstation, an Interpro running an Environ V version of
MicroStation, a PC, and an HP. This section describes some of the
problems that were encountered.
In general, DLM's should not use system libraries. This example violates
this rule because one purpose of this example is to illustrate how to
handle some of the difficult problems that arise in linking DLM's.
On the Intergraph platform, a DLM is a relocatable object file. To
create a relocatable object file, use the Unix utility ld to combine
object files. Specify -r in the command line to specify that the
output is a relocatable object file, not an executable file. ld must
be used to start the link. Neither acc or cc pass the -r flag to the
ld.
On the Intergraph platform, MicroStation can resolve symbols from a
shared library only if MicroStation is linked with that shared
library. Currently, only the tools and C shared libraries are
supported. The X windows version of ustation32, programs will be able
to use the X windows shared library.
In this example, the link is performed in 2 steps. First fileresl.out
is created. This resolves references to symbols that are to be
resolved from the system libraries instead of from MicroStation.
This step resolves as few symbols as possible. Then fileresl.out
is linked with the other object files to create fileio.out. There
are a lot of references unresolved in fileio.out. These are
all resolved at runtime when fileio.out is loaded. If the link
step only contained 1 step, and the link step that builds fileio.out
used the libraries, then these references would be resolved from
the libraries instead of from MicroStation. That could cause some
important data structures to be duplicated, possibly breaking the
heap management functions such as malloc and free.
Since nearly all standard C functions are available as built-in
functions, a portable DLM should not have to use any of the shared
libraries. In fact, many DLM's will not be linked with any libraries.
All of the references will be resolved at runtime from MicroStation's
built-ins. It should be able to have all of the symbols resolved from
MicroStation's built-ins at runtime.
On the SPARC Station the DLM is a sharable object file. This is done
automatically. There is nothing unusual in the compilation or link
steps, except that ".so" is specified as the file suffix for the
sharable object the link step creates.
On the SPARC, it is necessary for the DLM to provide intermediate
functions to call functions that are in the shared library. MDL
applications can not directly call functions from a system shared
library. The MDL application must call a function in the DLM that in
turn calls the function in the shared library. The DLM in this example
has a function fileio_perror that does nothing other than call perror
with the same parameters. This is needed because the runtime load step
would fail when MicroStation tried to get the address of perror for
the MDL application. The system call used for that would fail and
would terminate MicroStation. On other systems, it is possible to have
the MDL functions call library functions directly. For example, on the
Interpro the fileio_perror intermediate function is not required. In
this example, the intermediate functions are used regardless of
platform so that the code can be as similar as possible on all
platforms.
On the SPARC, do not specify the standard libraries in the Dynamic
Link Module's link step. If the link step does not specify the
standard libraries, the Dynamic Link Module still can use functions
and variables from those libraries. All of the symbols are resolved at
runtime. Starting with Release 4.1.2 of the SunOS, if
both MicroStation and the dynamic link module specify the same
shared library then at runtime the following message occurs:
"ld.so: conflicting usage of dlopen'ed dependents"
On the SPARC, MicroStation never unloads a DLM. There is a bug in the
SunOS that causes MicroStation to crash when a DLM is reloaded. To
get around this problem, MicroStation always keeps the DLM loaded.
This is most significant to developers who must restart MicroStation
to use a new version of a DLM.
On the HP700, the DLM is a shared library. All of the object files
must contain position-independent code. This is achieved by specifying
"+z" in the compilation step. Specify "-b" in the command line of the
load step to specify that the output file is a shared library.
On the PC, the DLM is a REX file that is created by the Phar Lap
linker and then processed by the BSI-supplied utility linkdlm to help
the runtime code find all references that need to be fixed up.
A REX file is a standard Phar Lap relocatable executable. The REX file
must be linked with a number of standard BSI-supplied object files and
libraries. Both linkdlm and MicroStation's runtime verify that these
files were included in the link step.
The object file ustnfrst.obj must be the first input file specified in
the link step. The library file dlmsyms.lib must be specified after
all of the object files. This contains definitions for all of the
symbols that can be resolved from MicroStation. ustnlast.lib must be
the last file in the link step.
After creating the REX file, run it through linkdlm. The command to
invoke linkdlm is
"linkdlm -r<rex file> -o<output file>"
where <rex file> specifies a rex file that was created by the Phar Lap
linker and <output file> specifies the outname of the output file. The
output will be used as a DLM.
Dynamic Link Modules - Debugging
Source level debugging is only available on the Intergraph platform.
To debug a DLM on an Interpro, just start MicroStation with dbg. After
the DLM has been loaded, hit ctrl-C to get into the debugger. Then you
can set breakpoints in the DLM. To invoke the debugger immediately
after the DLM is loaded but before the initialize function is called,
set a breakpoint on the function "dlink_debugHook". This MicroStation
function is called immediately after a DLM is loaded.
Dynamic Link Specifications - New Built-in Functions
This section documents the following built-in functions:
dlmSystem_callMdlFunction, dlmSystem_setFunction, dlmSystem_mdlMalloc,
dlmSystem_calloc, dlmSystem_mdlFree, dlmSystem_mdlRealloc,
dlmSystem_mdlFopen, dlmSystem_mdlFclose, dlmSystem_mdlTmpfile,
dlmSystem_mdlFreopen, mdlSystem_getCurrMdlDesc, mdlSystem_findMdlDesc,
and mdlSystem_getCurrTaskId
It also documents the following hook functions that can be defined in
the DLM: initialize, userHook_mdlUnload, userHook_dlmUnload.
The DLM does not need to use the names userHook_mdlUnload and
userHook_dlmUnload. These hook functions are designated to
MicroStation by address only using dlmSystem_setFunction.
The name initialize must be used for the initialization function.
MicroStation uses the DLM's symbol table to find the address of this
function.
The functions dlmSystem_mdlMalloc, dlmSystem_mdlCalloc,
dlmSystem_mdlRealloc, and dlmSystem_mdlFree have the same parameters
and return values as malloc, calloc, realloc, and free. These
dlmSystem_mdl... functions associate the memory with the current MDL
application. When that application is unloaded, the memory is
automatically freed. To allocate and free memory without associating
it with the current MDL application, use malloc, calloc, realloc, and
free.
The functions dlmSystem_mdlFopen, dlmSystem_mdlFclose,
dlmSystem_mdlTmpfile, and dlmSystem_mdlFreopen have the same
parameters and return values as fopen, fclose, tmpfile, and freopen.
These dlmSystem_mdl... functions associate the file pointer with the
current MDL application. When the application is unloaded, the file is
automatically closed. To manipulate files without associating them
with the MDL application, use the standard functions fopen, fclose,
tmpfile, and freopen.
Summary
#include "dlmsys.fdf"
int dlmSystem_callMdlFunction
(
void *mdlDescP,
MdlFunctionP functionOffset,
... /* Parameters for the MDL function */
)
Description
The dlmSystem_callMdlFunction function is used to call an MDL
function. The mdlDescP parameter points to the MDL descriptor for the
function to be called.
The functionOffset parameter is an offset to the function to be
called. This is an MDL function pointer.
The variable argument list represents the arguments to be passed to
the MDL function. Up to 15 arguments may be passed. MicroStation
automatically determines the number and types of arguments expected by
the function. (It does this by examining the function's header. This
header is actually part of the MDL program loaded by MDL. It is
created automatically by the MDL compiler.) Using this information,
MicroStation moves the arguments from MicroStation's stack to the MDL
application's stack and dispatches the function.
Return Value
dlmSystem_callMdlFunction returns the value returned by the MDL
application. It only returns integer values. If
dlmSystem_callMdlFunction is not able to call the function, then it
returns 0. This only happens if the offset is 0, or the pointer to the
MDL descriptor is NULL.
Summary
#include "dlmsys.fdf"
int dlmSystem_setFunction
(
int functionType,
void *dlmID,
int (*funcP)()
)
Description
The dlmSystem_setFunction function is used to designate a DLM user
hook. The functionType parameter specifies the type of hook. Valid
values are DLM_SYSTEM_MDL_UNLOAD and DLM_SYSTEM_DLM_UNLOAD.
The dlmID parameter identifies the DLM setting up the hook. This value
was supplied by MicroStation in the call to the DLM's initialization
function.
The funcP parameter specifies the function to be called when the
designated event occurs. A value of NULL cancels the outstanding hook.
Return Value
dlmSystem_setFunction returns SUCCESS if it was able to set up the
hook. Otherwise, it returns ERROR.
Summary
#include "mssystem.fdf"
void *mdlSystem_getCurrMdlDesc
(
void
)
void *mdlSystem_findMdlDesc
(
char *taskIdP
)
char *mdlSystem_getMdlTaskId
(
void *mdlDescP
)
Description
The mdlSystem_getCurrMdlDesc function is used to retrieve a pointer to
the MDL descriptor of the currently active MDL application. This
pointer is used a parameter to a number of functions.
The mdlSystem_findMdlDesc function is used to retrieve a pointer to
the MDL descriptor of the MDL application specified by taskIdP. The
string functionType points to is the task ID of an MDL application.
mdlSystem_findMdlDesc is not case sensitive. It makes a copy of the
string and converts it to upper case before starting the search.
The mdlSystem_getMdlTaskId function is used to retrieve a pointer to
the task ID of an MDL application. mdlDescP specifies the MDL
descriptor of a loaded MDL application.
Return Value
mdlSystem_getCurrMdlDesc and mdlSystem_findMdlDesc both return
pointers to MDL descriptors. mdlSystem_getCurrMdlDesc always returns a
non-NULL value. If no MDL application is active, then it returns a
pointer to MicroStation's MDL descriptor. mdlSystem_findMdlDesc
returns NULL if the specified task ID does not name a loaded MDL
application. mdlSystem_getMdlTaskId returns a pointer to the task ID
of the specified MDL application.
INITIALIZE
int initialize
(
char *fileNameP,
char *taskIdP,
void *dlmID,
unsigned long initParameter
)
Description
MicroStation calls the initialize function as the final step of
loading an MDL application that requires DLM. If the DLM is required
by more than 1 MDL program, then the DLM is only loaded once but the
initialize function is called for each MDL program.
The parameter fileNameP points to the name of the file that contains
the DLM. The name includes the entire path.
taskIdP points to the task ID of the MDL program being loaded.
dlmID is a pointer that uniquely identifies the DLM. The DLM should
use this value if it calls any functions that take a DLM ID as a
parameter. initParameter is the value specified with the %Version
command in the Dynamic Link Specification source file.
Return Value
initialize may return 0 to allow the load to continue. If initialize
returns a non-zero value then the load of the MDL program is aborted.
If no other MDL programs have the DLM loaded, then the DLM is also
unloaded.
userHook_mdlUnload, userHook_dlmUnload
void userHook_mdlUnload
(
void *mdlDescP,
unsigned char *taskIdP,
unsigned char *fileNameP
)
void userHook_dlmUnload
(
void
)
Description
MicroStation calls the userHook_mdlUnload user hook functions whenever
an MDL application is unloaded. Both the mdlDescP and the taskIdP
identify the MDL application being unloaded. Either parameter is
enough to uniquely identify the application. Both parameters are
supplied just as a matter of convenience. mdlDescP may or may not be
the same as the current MDL descriptor. Never depend on the value of
the current MDL descriptor when this unload hook is called.
MicroStation calls the userHook_dlmUnload function prior to unloading
the DLM that designated that hook.
Return Value
Both of these hook functions are type void. MicroStation ignores the
return values of both of these functions.
Feature:
MDL Debugger Changes
Description:
If source is compiled using make files similar to those distributed
with the MDL examples, then it is no longer necessary to use the
environment variable MS_DBGSOURCE to tell the debugger where to find
the source. These make files use the entire path to specify the names
of source files. These complete names are now stored with the object
files and MDL programs. The debugger first uses this information to
find the source files before trying to use the information in
MS_DBGSOURCE.
On the Intergraph platform, if the environment variable MS_DBGOUT is
set, the MDL debugger then uses the terminal session that started
MicroStation for input and output instead of using the MicroStation
debugger window. That way, the terminal session can be used for
debugging DLM's and an MDL program. The MDL debugger does not work in
curses mode. It only supports line mode. The MDL debugger supports
cntl-P for previous line, cntl-N for next line, cntl-B for back 1
character, cntl-F for forward 1 character, and backspace. It also
supports ESCAPE to clear the current command line.