Call-In is a framework supported by GT.M that allows a C/C++ program to invoke an M routine within the same process context. GT.M provides a well-defined Call-In interface packaged as a run-time shared library that can be linked into an external C/C++ program.

To facilitate Call-Ins to M routines, the GT.M distribution directory ($gtm_dist) contains the following files:

  1. libgtmshr.so - A shared library that implements the GT.M run-time system, including the Call-In API. If Call-Ins are used from a standalone C/C++ program, this library needs to be explicitly linked into the program. See Building Standalone Programs”, which describes the necessary linker options on each supported platforms.

    [Note]Note

    .so is the recognized shared library file extension on most UNIX platforms.

  2. mumps - The GT.M startup program that dynamically links with libgtmshr.so.

  3. gtmxc_types.h - A C-header file containing the declarations of Call-In API.

The following sections describe the files relevant to using Call-Ins.

The header file provides signatures of all Call-In interface functions and definitions of those valid data types that can be passed from C to M. FIS strongly recommends that these types be used instead of native types (int, char, float, and so on), to avoid possible mismatch problems during parameter passing.

gtmxc_types.h defines the following types that can be used in Call-Ins.

typedef struct {
    gtm_long_t length;
    gtm_char_t* address;
} gtm_string_t;

The pointer types defined above are 32-bit addresses on all 32-bit platforms. For 64-bit platforms, gtm_string_t* is a 64-bit address.

gtmxc_types.h also provides an input-only parameter type gtm_pointertofunc_t that can be used to obtain call-back function pointers via parameters in the external routine. If a parameter is specified as I:gtm_pointertofunc_t and if a numeric value (between 0-5) is passed for this parameter in M, GT.M interprets this value as the index into the callback table and passes the appropriate callback function pointer to the external routine.

[Note]Note

GT.M represents values that fit in 18 digits as numeric values, and values that require more than 18 digits as strings.

[Note]Note

GT.M MUMPS language runtime supports a maximum of 1MiB strings. Please take care to use 1MiB buffers for Output-only and Input-Output variables. Failure to do so could cause a segmentation violation if the called M routine writes more data into the supplied buffer than the caller allocated.

gtmxc_types.h also includes definitions for the following entry points exported from libgtmshr:

void gtm_hiber_start(gtm_uint_t mssleep);
void gtm_hiber_start_wait_any(gtm_uint_t mssleep)
void gtm_start_timer(gtm_tid_t tid, gtm_int_t time_to_expir, void (*handler)(), gtm_int_t hdata_len, void \
*hdata);
void gtm_cancel_timer(gtm_tid_t tid);

where:

gtm_hiber_start() always sleeps until the time expires; gtm_hiber_start_wait_any() sleeps until the time expires or an interrupt by any signal (including another timer). gtm_start_timer() starts a timer but returns immediately (no sleeping) and drives the given handler when time expires unless the timer is canceled.

[Important]Important

GT.M continues to support xc_* equivalent types of gtm_* for upward compatibility. gtmxc_types.h explicitly marks the xc_* equivalent types as deprecated.

The Call-In table file is a text file that contains the signatures of all M label references that get called from C. In order to pass the typed C arguments to the type-less M formallist, the enviroment variable GTMCI must be defined to point to the Call-In table file path. Each signature must be specified separately in a single line. GT.M reads this file and interprets each line according to the following convention (specifications withint box brackets "[]", are optional):

<c-call-name> : <ret-type> <label-ref> ([<direction>:<param-type>,...])

where,

<label-ref>: is the entry point (that is a valid label reference) at which GT.M starts executing the M routine being called-in

<c-call-name>: is a unique C identifier that is actually used within C to refer to <label-ref>

<direction>: is either I (input-only), O (output-only), or IO (input-output)

<ret-type>: is the return type of <label-ref>

[Note]Note

Since the return type is considered as an output-only (O) parameter, the only types allowed are pointer types and void. Void cannot be specified as parameter.

<param-type>: is a valid parameter type. Empty parentheses must be specified if no argument is passed to <label-ref>

The <direction> indicates the type of operation that GT.M performs on the parameter read-only (I), write-only (O), or read-write (IO). All O and IO parameters must be passed by reference, that is as pointers since GT.M writes to these locations. All pointers that are being passed to GT.M must be pre-allocated. The following table details valid type specifications for each direction.

Here is an example of Call-In table (calltab.ci) for piece.m (see “Example: Calling GT.M from a C Program”):

print     :void            display^piece()
getpiece  :gtm_char_t*     get^piece(I:gtm_char_t*, I:gtm_char_t*, I:gtm_long_t)
setpiece  :void            set^piece(IO:gtm_char_t*, I:gtm_char_t*, I:gtm_long_t, I:gtm_char_t*)
pow       :gtm_double_t*   pow^piece(I:gtm_double_t, I:gtm_long_t)
powequal  :void            powequal^piece(IO:gtm_double_t*, I:gtm_long_t)
piece     :gtm_double_t*   pow^piece(I:gtm_double_t, I:gtm_long_t)
[Note]Note

The same entryref can be called by different C call names (for example, pow, and piece). However, if there are multiple lines with the same call name, only the first entry will be used by GT.M. GT.M ignores all subsequent entries using a call name. Also, note that the second and third entries, although shown here as wrapped across lines, must be specified as a single line in the file.

This section is further broken down into 6 subsections for an easy understanding of the Call-In interface. The section is concluded with an elaborate example.

gtm_status_t gtm_init(void);

If the base program is not an M routine but a standalone C program, gtm_init() must be called (before calling any GT.M functions), to initialize the GT.M run-time system.

gtm_init() returns zero (0) on success. On failure, it returns the GT.M error status code whose message can be read into a buffer by immediately calling gtm_zstatus() (see Print Error Messages”). Duplicate invocations of gtm_init() are ignored by GT.M.

If Call-Ins are used from an external call function (that is, a C function that has itself been called from M code), gtm_init() is not needed, because GT.M is initialized before the External Call. All gtm_init() calls from External Calls functions are ignored by GT.M.

GT.M provides 2 interfaces for calling a M routine from C. These are:

gtm_cip offers better performance on calls after the first one.

gtm_status_t gtm_cip(ci_name_descriptor *ci_info, ...);

The variable argument function gtm_cip() is the interface that invokes the specified M routine and returns the results via parameters.

ci_name_descriptor has the following structure:

typedef struct
{
  gtm_string_t rtn_name;
  void* handle;
} ci_name_descriptor;

rtn_name is a C character string indicating the corresponding <lab-ref> entry in the Call-In table.

The handle is GT.M private information initialized by GT.M on the first call-in and to be provided unmodified to GT.M on subsequent calls. If application code modifies it, it will corrupt the address space of the process, and potentially cause just about any bad behavior that it is possible for the process to cause, including but not limited to process death, database damage and security violations.

The gtm_cip() call must follow the following format:

status = gtm_cip(<ci_name_descriptor> [, ret_val] [, arg1] ...);

First argument: ci_name_descriptor, a null-terminated C character string indicating the alias name for the corresponding <lab-ref> entry in the Call-In table.

Optional second argument: ret_val, a pre-allocated pointer through which GT.M returns the value of QUIT argument from the (extrinsic) M routine. ret_val must be the same type as specified for <ret-type> in the Call-In table entry. The ret_val argument is needed if and only if <ret-type> is not void.

Optional list of arguments to be passed to the M routine's formallist: the number of arguments and the type of each argument must match the number of parameters, and parameter types specified in the corresponding Call-In table entry. All pointer arguments must be pre-allocated. GT.M assumes that any pointer, which is passed for O/IO-parameter points to valid write-able memory.

The status value returned by gtm_cip() indicates the GT.M status code; zero (0), if successful, or a non-zero; $ZSTATUS error code on failure. The $ZSTATUS message of the failure can be read into a buffer by immediately calling gtm_zstatus() (for details, see Print Error Messages”).

Here are some working examples of C programs that use call-ins to invoke GT.M. Each example is packaged in a zip file which contains a C program, a call-in table, and a GT.M API. To run an example, click Download icon and follow the compiling and linking instructions in the comments of the C program.

Example

Download information

gtmaccess.c (gtm_ci interface)

Click Download gtmci_gtmaccess.zip to download or open directly from http://tinco.pair.com/bhaskar/gtm/doc/books/pg/UNIX_manual/gtmci_gtmaccess.zip

gtmaccess.c (gtm_cip interface)

Click Download gtmcip_gtmaccess.zip to download or open directly from http://tinco.pair.com/bhaskar/gtm/doc/books/pg/UNIX_manual/gtmcip_gtmaccess.zip

cpiece.c (gtm_ci interface)

Click Download gtmci_cpiece.zip to download or open directly from http://tinco.pair.com/bhaskar/gtm/doc/books/pg/UNIX_manual/gtmci_cpiece.zip

Call-ins can be nested by making an external call function in-turn call back into GT.M. Each gtm_ci() called from an External Call library creates a call-in base frame at $ZLEVEL 1 and executes the M routine at $ZLEVEL 2. The nested call-in stack unwinds automatically when the External Call function returns to GT.M.

GT.M currently allows up to 10 levels of nesting, if TP is not used, and less than 10 if GT.M supports call-ins from a transaction (see “Rules to Follow in Call-Ins”). GT.M reports the CIMAXLEVELS error when the nesting reaches its limit.

Following are the GT.M commands, Intrinsic Special Variables, and functions whose behavior changes in the context of every new nested call-in environment.

ZGOTO 0 (zero) returns to the processing of the invoking non-M routine as does ZGOTO 1 (one) with no entryref, while ZGOTO 1:entryref replaces the originally invoked M routine and continues M execution.

$ZTRAP/$ETRAP NEW'd at level 1 (in GTM$CI frame).

$ZLEVEL initializes to one (1) in GTM$CI frame, and increments for every new stack level.

$STACK initializes to zero (0) in GTM$CI frame, and increments for every new stack level.

$ESTACK NEW'd at level one (1) in GTM$CI frame.

$ECODE/$STACK() initialized to null at level one (1) in GTM$CI frame.

[Note]Note

After a nested call-in environment exits and the external call C function returns to M, the above ISVs and Functions restore their old values.

  1. External calls must not be fenced with TSTART/TCOMMIT if the external routine calls back into mumps using call-in mechanism. GT.M reports the CITPNESTED error if nested call-ins are invoked within a TP fence since GT.M currently does not handle TP support across multiple call-in invocations.

  2. The external application should never call exit() unless it has called gtm_exit() previously. GT.M internally installs an exit handler that should never be bypassed.

  3. The external application should never use any signals when GT.M is active since GT.M reserves them for its internal use. GT.M provides the ability to handle SIGUSR1 within M (see “$ZINTerrupt” for more information). An interface is provided by GT.M for timers.

  4. FIS recommends the use of gtm_malloc() and gtm_free() for memory management by C code that executes in a GT.M process space for enhanced performance and improved debugging. Always use gtm_malloc to allocate returns for pointer types to prevent memory leaks.

  5. GT.M performs device input using the read() system service. UNIX documentation recommends against mixing this type of input with buffered input services in the fgets() family and ignoring this recommendation is likely to cause loss of input that is difficult to diagnose and understand.

loading table of contents...