Using the Caché Callin API
The Callin Interface
[Back] [Next]
   
Server:docs1
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

Caché offers a Callin interface you can use from within C programs to execute Caché commands and evaluate Caché expressions. This chapter describes this interface and includes the following sections:

The Callin interface permits a wide variety of applications. For example, you can use it to make Caché ObjectScript available from an integrated menu or GUI. If you gather information from an external device, such as an Automatic Teller Machine or piece of laboratory equipment, the Callin interface lets you store this data in a Caché database. Although Caché currently supports only C and C++ programs, any language that uses the calling standard for that platform (OpenVMS, UNIX®, Windows) can invoke the Callin functions.
See Using the Callin Functions for a quick review of Callin functions. For detailed reference material on each Callin function, see the Callin Function Reference.
The callin.h Header File
The callin.h header file defines prototypes for these functions, which allows your C compiler to test for valid parameter data types when you call these functions within your program. You can add this file to the list of #include statements in your C program:
#include "callin.h"
The callin.h file also contains definitions of parameter values you use in your calls, and includes various #defines that may be of use. These include operating-system–specific values, error codes, and values that determine how Caché behaves.
You can translate the distributed header file, callin.h. However, callin.h is subject to change and you must track any changes if you create a translated version of this file. InterSystems Worldwide Support Center does not handle calls about unsupported languages.
Return values and error codes
Most Callin functions return values of type int, where the return value does not exceed the capacity of a 16-bit integer. Returned values can be CACHE_SUCCESS, a Caché error, or a Callin interface error.
There are two types of errors:
callin.h defines symbols for all Caché and interface errors, including CACHE_SUCCESS (0) and CACHE_FAILURE (-1). You can translate Caché errors (positive integers) by making a call to the Callin function CacheErrxlate.
8-bit and Unicode String Handling
Caché Callin functions that operate on strings have both 8-bit and Unicode versions. These functions use a suffix character to indicate the type of string that they handle:
For best performance, use the kind of string native to your installed version of Caché.
8-bit String Data Types
Caché supports the following data types that use local 8-bit string encoding:
The type definition for these is:
#define CACHE_MAXSTRLEN 32767
typedef struct {
   unsigned short  len;
   Callin_char_t   str[CACHE_MAXSTRLEN];
} CACHE_ASTR, *CACHE_ASTRP;
The CACHE_ASTR and CACHE_ASTRP structures contain two elements:
CACHE_MAXSTRLEN is the maximum length of a string that is accepted or returned. A parameter string need not be of length CACHE_MAXSTRLEN nor does that much space have to be allocated in the program.
2–byte Unicode Data Types
Caché supports the following Unicode-related data types on platforms that use 2–byte Unicode characters:
The type definition for these is:
typedef struct { 
   unsigned short len; 
   unsigned short str[CACHE_MAXSTRLEN]; 
} CACHEWSTR, *CACHEWSTRP;
The CACHEWSTR and CACHEWSTRP structures contain two elements:
CACHE_MAXSTRLEN is the maximum length of a string that is accepted or returned. A parameter string need not be of length CACHE_MAXSTRLEN nor does that much space have to be allocated in the program.
On Unicode-enabled versions of Caché, there is also the data type CACHE_WSTRING, which represents the native string type on 2–byte platforms. CacheType returns this type. Also, CacheConvert can specify CACHE_WSTRING as the data type for the return value; if this type is requested, the result is passed back as a counted Unicode string in a CACHEWSTR buffer.
4–byte Unicode Data Types
Caché supports the following Unicode-related data types on platforms that use 4–byte Unicode characters:
The type definition for these is:
typedef struct {
   unsigned int len;
   wchar_t str[CACHE_MAXSTRLEN];
} CACHEHSTR, *CACHEHSTRP;
The CACHEHSTR and CACHEHSTRP structures contain two elements:
CACHE_MAXSTRLEN is the maximum length of a string that is accepted or returned. A parameter string need not be of length CACHE_MAXSTRLEN nor does that much space have to be allocated in the program.
On Unicode-enabled versions of Caché, there is also the data type CACHE_HSTRING, which represents the native string type on 4–byte platforms. CacheType returns this type. Also, CacheConvert can specify CACHE_HSTRING as the data type for the return value; if this type is requested, the result is passed back as a counted Unicode string in a CACHEHSTR buffer.
System-neutral Symbol Definitions
The allowed inputs and outputs of some functions vary depending on whether they are running on an 8-bit system or a Unicode system. For many of the “A” (ASCII) functions, the arguments are defined as accepting a CACHESTR, CACHE_STR, CACHESTRP, or CACHE_STRP type. These symbol definitions (without the “A” , “W”, or “H”) can conditionally be associated with either the 8-bit or Unicode names, depending on whether the symbols CACHE_UNICODE and CACHE_WCHART are defined at compile time. This way, you can write source code with neutral symbols that works with either local 8-bit or Unicode encodings.
The following excerpt from callin.h illustrates the concept:
#if defined(CACHE_UNICODE) /* Unicode character strings */
#define   CACHESTR      CACHEWSTR
#define   CACHE_STR     CACHEWSTR
#define   CACHESTRP     CACHEWSTRP
#define   CACHE_STRP    CACHEWSTRP
#define   CACHE_STRING  CACHE_WSTRING

#elif defined(CACHE_WCHART)  /* wchar_t character strings */
#define   CACHESTR      CACHEHSTR
#define   CACHE_STR     CACHEHSTR
#define   CACHESTRP     CACHEHSTRP
#define   CACHE_STRP    CACHEHSTRP
#define   CACHE_STRING  CACHE_HSTRING

#else                  /* 8-bit character strings */
#define   CACHESTR      CACHE_ASTR
#define   CACHE_STR     CACHE_ASTR
#define   CACHESTRP     CACHE_ASTRP
#define   CACHE_STRP    CACHE_ASTRP
#define   CACHE_STRING  CACHE_ASTRING
#endif
Using Caché Security Functions
Two functions are provided for working with Caché passwords:
There are CacheSecureStart and CacheChangePassword functions for ASCII "A", Unicode "W", and Unicode "H" installs. The new functions either narrow, widen or "use as is" the passed in parameters, store them in the new Callin data area, then eventually call the CacheStart entry point.
CacheStart and CacheSecureStart pin and pout parameters can be passed as NULL, which indicates that the platform's default input and output device should be used.
Using Callin with Multithreading
Caché has been enhanced so that Callin can be used by threaded programs running under some versions of Windows and UNIX® (see “Other Supported Features” in InterSystems Supported Platforms for a list). A program can spawn multiple threads (pthreads in a UNIX® environment) and each thread can establish a separate connection to Caché by calling CacheSecureStart. Threads may not share a single connection to Caché; each thread which wants to use Cache must call CacheSecureStart. If a thread attempts to use a Callin function and it has not called CacheSecureStart, a CACHE_NOCON error is returned.
A threaded application must link against cachet.o or the shared library, cachet.so. On UNIX® and Linux they may alternatively load the shared library dynamically. On Windows, due to the implementation of thread local storage the cachet.dll library cannot be dynamically loaded. The program should be careful not to exit until all of the threads which have entered Caché have called CacheEnd to shut down their connections. Failure to shut down each connection with CacheEnd may hang the instance, requiring a restart.
If CacheSecureStart is being used, to specify credentials as part of the login, each thread must call CacheSecureStart and provide the correct username/password for the connection, since credentials are not shared between the threads. There is a performance penalty within Caché using threads because of the extra code the C compiler has to generate to access thread local storage (which uses direct memory references in non-threaded builds).
A sample program, sampcallint.c, is provided on all platforms where this feature is supported. The vc8 project, and the UNIX® Makefiles, include instructions to build a sample threaded Callin application on the relevant platforms.
Threads and UNIX® Signal Handling
On UNIX®, Caché uses a number of signals. If your application uses the same signals, you should be aware of how Caché deals with them. All signals have a default action specified by the OS. Applications may choose to leave the default action, or can choose to handle or ignore the signal. If the signal is handled, the application may further select which threads will block the signal and which threads will receive the signal. Some signals cannot be blocked, ignored, or handled. Since the default action for many signals is to halt the process, leaving the default action in place is not an option. The following signals cannot be caught or ignored, and terminate the process:
SIGNAL DISPOSITION
SIGKILL terminate process immediately
SIGSTOP stop process for later resumption
The actions that an application establishes for each signal are process-wide. Whether or not the signal can be delivered to each thread is thread-specific. Each thread may specify how it will deal with signals, independently of other threads. One thread may block all signals, while another thread may allow all signals to be sent to that thread. What happens when a signal is sent to the thread depends on the process-wide handling established for that signal.
Caché Signal Processing
Caché integrates with application signal handling by saving application handlers and signal masks, then restoring them at the appropriate time. Caché processes signals in the following ways:
Generated signals
Caché installs its own signal handler for all generated signals. It saves the current (application) signal handler. If the thread catches a generated signal, the Caché signal handler disconnects the thread from Caché, calls the applications signal handling function (if any), then does pthread_exit.
Since signal handlers are process-wide, threads not connected to Caché will also go into the Caché handler. If Caché detects that the thread is not connected, it calls the application handler and then does pthread_exit.
Synchronous Signals
Caché establishes signal handlers for all synchronous signals, and unblocks these signals for each thread when the thread connects to Caché (see Synchronous Signals for details).
Asynchronous Signals
Caché handles all asynchronous signals that would terminate the process (see Asynchronous Signals for details).
Save/Restore Handlers
Caché saves the signal state when the first thread connects to it. When the last thread disconnects, Caché restores the signal state for every signal that it has handled.
Save/Restore Thread Signal Mask
The thread signal mask is saved on connect, and restored when the thread disconnects.
Synchronous Signals
Synchronous signals are generated by the application itself (for example, SIGSEGV). Caché establishes signal handlers for all synchronous signals, and unblocks these signals for each thread when it connects to Caché.
Synchronous signals are caught by the thread that generated the signal. If the application has not specified a handler for a signal it has generated (for example, SIGSEGV), or if the thread has blocked the signal, then the OS will halt the entire process. If the thread enters the signal handler, that thread may exit cleanly (via pthread_exit) with no impact to any other thread. If a thread attempts to return from the handler, the OS will halt the entire process. The following signals cause thread termination:
SIGNAL DISPOSITION
SIGABRT process abort signal
SIGBUS bus error
SIGEMT EMT instruction
SIGFPE floating point exception
SIGILL illegal instruction
SIGSEGV access violation
SIGSYS bad argument to system call
SIGTRAP trace trap
SIGXCPU CPU time limit exceeded (setrlimit)
Asynchronous signals
Asynchronous signals are generated outside the application (for example, SIGALRM, SIGINT, and SIGTERM). Caché handles all asynchronous signals that would terminate the process.
Asynchronous signals may be caught by any thread that has not blocked the signal. The system chooses which thread to use. Any signal whose default action is to cause the process to exit must be handled, with at least one thread eligible to receive it, or else it must be specifically ignored.
The application must establish a signal handler for those signals it wants to handle, and must start a thread that does not block those signals. That thread will then be the only one eligible to receive the signal and handle it. Both the handler and the eligible thread must exist before the application makes its first call to CacheStart. On the first call to CacheStart, the following actions are performed for all asynchronous signals that would terminate the process:
The following signals are affected by this process:
SIGNAL DISPOSITION
SIGALRM timer
SIGCHLD blocked by threads
SIGDANGER ignore if unhandled
SIGHUP ignore if unhandled
SIGINT ignore if unhandled
SIGPIPE ignore if unhandled
SIGQUIT ignore if unhandled
SIGTERM If SIGTERM is unhandled, Cache will handle it. On receipt of a SIGTERM signal, the Cache handler will disconnect all threads and no new connections will be permitted. Handlers for SIGTERM are not stacked.
SIGUSR1 inter-process communication
SIGUSR2 inter-process communication
SIGVTALRM virtual timer
SIGXFSZ Caché asynchronous thread rundown
Callin Programming Tips
Topics in this section include:
Tips for All Callin Programs
Your external program must follow certain rules to avoid corrupting Caché data structures, which can cause a system hang.
Tips for Windows
These tips apply only to Windows.
Tips for UNIX®, Linux, and Mac OS
These tips apply only to UNIX®, Linux, and Mac OS.
Tips for OpenVMS
These tips apply only to OpenVMS.
Running Sample Programs on Windows
The \dev\cache\callin directory contains source files, header files, and project directories for building Caché Callin applications. These projects provide a simple demonstration of how to use some high level Caché call-in functions.
In order to build these projects, open any of the .vcproj files (for Visual C++ 2005), or .dsp files (for Visual C++ 2003). Double-click on the file, or run your Visual C++ application and select File>Open>Project/Solution to open the project file.
Note:
You can run call-in programs on Windows 2000, but you have to compile them on Windows XP or newer, since Visual Studio 2008 and the Windows 2008 SDK only go back to Windows XP. The Visual Studio 2008 redistributables are supported on Windows 2000, but there does not appear to be a compatible compiler that is supported on Windows 2000.
The shdir.c file has been already initialized with the path to your Caché mgr directory. For a default installation, the shdir.c file will look like this:
char shdir[256] = "c:\\cachesys\\mgr";
The Callin interface provides the CACHESETDIR entry point to dynamically set the name of the manager directory at runtime. The shared library version of cache requires the use of this interface to find the installation’s manager’s directory.
Two sample C programs are provided. The sampcallin.c program is the standard Callin application example, and sampcallint.c is the thread-safe Callin application example.
There are two projects for sampcallin.c and a project for sampcallint.c. These projects are:
After each of the projects is built, it may be run in the Visual C++ environment.
When a project is built from the cache shared library, using cache.dll, the location of cache.dll must be defined in the user's PATH environment variable, except when the file is located in the current directory.
Running Sample Programs on UNIX® and Linux
The directory dev/cache/callin/samples contains a complete Makefile to build Callin samples. This replaces the clink file found in previous releases.
A shared library version of cache is now provided in addition to the cache object file. The UNIX® Makefiles build two Callin sample applications: one using the cache object, and one using the libcache shared library.
Run make in the dev/cache/callin/samples directory. The supplied Makefile will build a cache using the czf interface, a standard Callin application, and a shared library Callin application.
The file shdir.c is set to the appropriate value during installation, so no editing is required.
The Callin interface provides the CACHESETDIR entry point to dynamically set the name of the manager directory at runtime.
Using Makefiles on UNIX®
The UNIX® Makefiles for building Callin samples and customer Callin programs are run by the make command. make automatically finds the file called Makefile in the current directory. Thus, running make in the samples directory produces a sample Callin executable.
When invoking make, use the SRC variable to specify the name of the source program. The default is sampcallin. To change the name of the source file being built, override the SRC variable on the command line. For example, with a Callin program called mycallin.c, the command is:
   make SRC=mycallin
Setting Permissions for Callin Executables on UNIX®
Caché executables, files, and resources such as shared memory and operating system messages, are owned by a user selected at installation time (the installation owner) and a group with a default name of cacheusr (you can choose a different name at installation time). These files and resources are only accessible to processes that either have this user ID or belong to this group. Otherwise, attempting to connect to Caché results in protection errors from the operating system (usually specifying that access is denied); this occurs prior to establishing any connection with Caché.
A Callin program can only run if its effective group ID is cacheusr. To meet this condition, one of the following must be true:
Running Sample Programs on OpenVMS
To compile, link, and run your Callin program on OpenVMS:
  1. Make sure Caché is running. This step is necessary as this procedure accesses some of the image files.
  2. Compile your program by entering the command:
    $ CC MYCALLIN
    Note:
    To use IEEE floats on OpenVMS Alpha systems, compile your Callin program with the /float=ieee_float compiler qualifier. (On OpenVMS Itanium systems, this is the default.)
  3. Link the sampcallin.c object with the supplied Callin file, CLINK.OPT. See one of the following sections for details:
  4. Run the executable by entering:
    $ RUN MYCALLIN
Due to 32/64–bit pointer conversion issues on OpenVMS, you should not build Caché Callin modules with 64–bit pointers, that is compiler option /pointersize=64. Use the default pointer size of 32 bits.
Files Supplied
Files on your distribution medium that pertain to the Caché Callin interface include the following:
Using CLINK.OPT on Alpha Systems
Use CLINK.OPT with the LINK command for OpenVMS Alpha systems. CLINK.OPT is a linker options file that contains the lines:
CACHE.EXE/SHAREABLE
SYS$LIBRARY:VAXCTRL/LIBRARY
Link the sampcallin.c object with CLINK.OPT by entering:
$ LINK MYCALLIN,CLINK/OPT,SYS$LIBRARY:VAXCRTL/LIB
or
$ LINK/EXE=MYCALLIN SYS$INPUT/OPTION MYCALLIN.OBJ 
    SYS$LIBRARY:VAXCRTL/LIB CACHESYS:CACHE/SHARE <CTRL-Z>
In order to support multiple simultaneous versions of Caché, a user-defined Callin executable needs to know both where the appropriate CACHE.EXE is located and where the corresponding Caché manager's directory is located. Under the present structure, the executable is kept in the bin subdirectory beneath the installation directory and the manager's directory is the mgr subdirectory.
To successfully load and run a Callin executable, define two process logicals:
For example:
DEFINE CACHE DKA0:[CACHESYS.BIN]CACHE.EXE
DEFINE CACHESYS DKA0:[CACHESYS.MGR]
For the default configuration or a machine with only one installation, you can use the system logicals that point to its files. System logical CACHESYS already gives the location of the manager's directory, so you need only provide the location of the executable:
DEFINE CACHE CACHEBIN:CACHE.EXE
If you invoke a Callin program that has been linked against a different CACHE.EXE than the one specified by the CACHE logical, then unpredictable behavior may result.
To specify the location of the CACHE.EXE to link against, your options are to:
The following example assumes that CACHE.EXE is in DKA0:[CACHESYS.BIN] and that there is a single user source file called mycallin.c. To compile the source, the command is:
$ CC MYCALLIN
To link the executable, the commands are:
$ LINK/EXECUTABLE=MYCALLIN MYCALLIN,  SYS$INPUT:/OPTIONS
DKA0:[CACHESYS.BIN]CACHE.EXE/SHAREABLE
SYS$LIBRARY:VAXCRTL/LIBRARY
<Ctrl-Z>
or else edit CLINK.OPT to read:
DKA0:[CACHESYS.BIN]CACHE.EXE/SHAREABLE
SYS$LIBRARY:VAXCRTL/LIBRARY
and call LINK this way:
$ LINK/EXECUTABLE=MYCALLIN MYCALLIN,  CLINK/OPTIONS
Using CLINK.OPT on Itanium Systems
Use CLINK.OPT with the LINK command for OpenVMS Itanium systems. CLINK.OPT is a linker options file that contains the line:
CKERNEL.EXE/SHAREABLE
(CKERNEL.EXE is a shared library image. The CACHE.EXE file is an executable image that contains a stub linked against CKERNEL.EXE). Link the sampcallin.c object with CLINK.OPT by entering:
$ LINK MYCALLIN,CLINK/OPT
or
$ LINK/EXE=MYCALLIN SYS$INPUT/OPTION MYCALLIN.OBJ 
    CACHESYS:CKERNEL/SHARE <CTRL-Z>
In order to support multiple simultaneous versions of Caché, a user-defined Callin executable needs to know both where the appropriate CKERNEL.EXE is located and where the corresponding Caché manager's directory is located. Under the present structure, the executable is kept in the bin subdirectory beneath the installation directory and the manager's directory is the mgr subdirectory.
To successfully load and run a Callin executable, define two process logicals:
For example:
DEFINE CKERNEL DKA0:[CACHESYS.BIN]CKERNEL.EXE
DEFINE CACHESYS DKA0:[CACHESYS.MGR]
For the default configuration or a machine with only one installation, you can use the system logicals that point to its files. System logical CACHESYS already gives the location of the manager's directory, so you need only provide the location of the executable:
DEFINE CKERNEL CACHEBIN:CKERNEL.EXE
If you invoke a Callin program that has been linked against a different CKERNEL.EXE than the one specified by the CKERNEL logical, then unpredictable behavior may result.
To specify the location of the CKERNEL.EXE to link against, your options are to:
The following example assumes that CKERNEL.EXE is in DKA0:[CACHESYS.BIN] and that there is a single user source file called mycallin.c. To compile the source, the command is:
$ CC MYCALLIN
To link the executable, the commands are:
$ LINK/EXECUTABLE=MYCALLIN MYCALLIN,  SYS$INPUT:/OPTIONS
DKA0:[CACHESYS.BIN]CKERNEL.EXE/SHAREABLE
<Ctrl-Z>
or else edit CLINK.OPT to read:
DKA0:[CACHESYS.BIN]CKERNEL.EXE/SHAREABLE
and call LINK this way:
$ LINK/EXECUTABLE=MYCALLIN MYCALLIN,  CLINK/OPTIONS