The functions in programs increment and decrement are now available to GT.M through the shareable library libcrement.sl or libcrement.so, or though the DLL as libcrement.dll, depending on the specific platform. The suffix .sl is used throughout the following examples to represent .sl, .so, or .dll. Be sure to use the appropriate suffix for your platform.

GT.M uses an "external call table" to map the typeless data of M into the typed data of C, and vice versa. The external call table has a first line containing the pathname of the shareable library file followed by one or more specification lines in the following format:

entryref: return-value routine-name (parameter, parameter, ... ) [: SIGSAFE]      

The optional case-insensitive keyword SIGSAFE following the parameter list specifies the external call does not create its own signal handlers; this allows GT.M to avoid burdensome signal handler coordination for the external call. By default, GT.M saves and restores signal setups for external calls.

entryref is an M entryref, return-value is gtm_long_t, gtm_status_t, or void, and parameters are in the format:

direction:type [num]

where [num] indicates a pre-allocation value explained later in this chapter.

Legal directions are I, O, or IO for input, output, or input/output, respectively.

The following table describes the legal types defined in the C header file $gtm_dist/gtmxc_types.h:

Type : Usage

void: Specifies that the function does not return a value.

gtm_status_t : Type int. If the function returns zero (0), then the call was successful. If it returns a non-zero value, GT.M will signal an error upon returning to M.

gtm_long_t : 32-bit signed integer on 32-bit platforms and 64-bit signed integer on 64-bit platforms.

gtm_ulong_t : 32-bit unsigned integer on 32-bit platforms and 64-bit signed integer on 64-bit platforms.

gtm_long_t* : For passing a pointer to long [integers].

gtm_float_t* : For passing a pointer to floating point numbers.

gtm_double_t* : Same as above, but double precision.

gtm_char_t*: For passing a "C" style string - null terminated.

gtm_char_t** : For passing a pointer to a "C" style string.

gtm_string_t* : For passing a structure in the form {int length;char *address}. Useful for moving blocks of memory to or from GT.M.

gtm_pointertofunc_t : For passing callback function pointers. For details see “Callback Mechanism”.

[Note]Note

If an external call's function argument is defined in the external call table, GT.M allows invoking that function without specifying a value of the argument. All non-trailing and output-only arguments arguments which do not specify a value translate to the following default values in C:

  • All numeric types: 0

  • gtm_char_t * and gtm_char_t **: Empty string

  • gtm_string_t *: A structure with 'length' field matching the preallocation size and 'address' field being a NULL pointer.

In the mathpak package example, the following invocation translate inval to the default value, that is, 0.

GTM>do &mathpak.increment(,.outval)

If an external call's function argument is defined in the external call table and that function is invoked without specifying the argument, ensure that the external call function appropriately handles the missing argument. As a good programming practice, always ensure that count of arguments defined in the external call table matches the function invocation.

To protect the process, GT.M turns any return values containing a null pointer to an empty string value and, for the first occurrence in a process, sends one XCRETNULLREF syslog message. If an external call sets a gtm_string length to a negative value, to protect the process, GT.M turns any return with a negative length to an empty string value and, for the first occurrence in a process, sends one XCCONVERT syslog message.

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:

  • mssleep - milliseconds to sleep

  • tid - unique timer id value

  • time_to_expir - milliseconds until timer drives given handler

  • handler - function pointer to handler to be driven

  • hdata_len - 0 or length of data to pass to handler as a parameter

  • hdata - NULL or address of data to pass to handler as a parameter

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.

  • Parameter-types that interface GT.M with non-M code using C calling conventions must match the data-types on their target platforms. Note that most addresses on 64-bit platforms are 8 bytes long and require 8 byte alignment in structures whereas all addresses on 32-bit platforms are 4 bytes long and require 4-byte alignment in structures.

  • Though strings with embedded zeroes are sent as input to external routines, embedded zeroes in output (or return value) strings of type gtm_char_t may cause string truncation because they are treated as terminator.

  • If your interface uses gtm_long_t or gtm_ulong_t types but your interface code uses int or signed int types, failure to revise the types so they match on a 64-bit platform will cause the code to fail in unpleasant, potentially dangerous and hard to diagnose ways.

The first parameter of each called routine is an int (for example, int argc in decrement.c and increment.c) that specifies the number of parameters passed. This parameter is implicit and only appears in the called routine. It does not appear in the call table specification, or in the M invocation. If there are no explicit parameters, the call table specification will have a zero (0) value because this value does not include itself in the count. If there are fewer actual parameters than formal parameters, the call is determined from the parameters specified by the values supplied by the M program. The remaining parameters are undefined. If there are more actual parameters than formal parameters, GT.M reports an error.

There may be only a single occurrence of the type gtm_status_t for each entryref.

To support Database Encryption, GT.M provides a reference implementation which resides in $gtm_dist/plugin/gtmcrypt.

The reference implementation includes:

To support the implementation of a reference implementation, GT.M provides additional C structure types (in the gtmxc_types.h file):

Although not required to be used by a customized plugin implementation, GT.M provides (and the reference implementation uses) the following functions for uniquely identifying files:

Mumps, MUPIP and DSE processes dynamically link to the plugin interface functions that reside in the shared library. The functions serve as software "shims" to interface with an encryption library such as libmcrypt or libgpgme / libgcrypt.

The plugin interface functions are:

A GT.M database consists of multiple database files, each of which has its own encryption key, although you can use the same key for multiple files. Thus, the gtmcrypt* functions are capable of managing multiple keys for multiple database files. Prototypes for these functions are in gtmcrypt_interface.h.

The core plugin interface functions, all of which return a value of type gtm_status_t are:

More detailed descriptions follow.

The complete source code for reference implementations of these functions is provided, licensed under the same terms as GT.M. You are at liberty to modify them to suit your specific GT.M database encryption needs. Check your GT.M license if you wish to consider redistributing your changes to others.

For more information and examples, refer to the Database Encryption Technical Bulletin.

The definition of parameters passed by reference with direction output can include specification of a pre-allocation value. This is the number of units of memory that the user wants GT.M to allocate before passing the parameter to the external routine. For example, in the case of type gtm_char_t *, the pre-allocation value would be the number of bytes to be allocated before the call to the external routine.

Specification of a pre-allocation value should follow these rules:

[Important]Important

Pre-allocation is optional for all output-only parameters except gtm_string_t * and gtm_char_t *. Pre-allocation yields better management of memory for the external call. When an external call exceeds its specified preallocation (gtm_string_t * or gtm_char_t * output), GT.M produces the EXCEEDSPREALLOC error. In the case the user allocates space for the character pointer inside a gtm_string_t * type output parameter, a length field longer than the specified preallocate size for the output parameter does not cause an EXCEEDSPREALLOC error.

GT.M exposes certain functions that are internal to the GT.M runtime library for the external calls via a callback mechanism. While making an external call, GT.M populates and exposes a table of function pointers containing addresses to call-back functions.

The external routine can access and invoke a call-back function in any of the following mechanisms:

[Note]Note

FIS strongly discourages the use of signals, especially SIGALARM, in user written C functions. GT.M assumes that it has complete control over any signals that occur and depends on that behavior for recovery if anything should go wrong. The use of exposed timer APIs should be considered for timer needs.

Since both GT.M runtime environment and the external C functions execute in the same process space, the following restrictions apply to the external functions:

foo: void bar (I:gtm_float_t*, O:gtm_float_t*)

There is one external call table for each package. The environment variable "GTMXC" must name the external call table file for the default package. External call table files for packages other than the default must be identified by environment variables of the form "GTMXC_name".

The first of the external call tables is the location of the shareable library. The location can include environment variable names.

Example:

% echo $GTMXC_mathpak
/user/joe/mathpak.xc
% echo lib /usr/
% cat mathpak.xc
$lib/mathpak.sl
exp: gtm_status_t xexp(I:gtm_float_t*, O:gtm_float_t*)
% cat exp.c
...
int xexp(count, invar, outvar)
int count;
float *invar;
float *outvar;
       {
        ...
       }
% gtm
... 
GTM>d &mathpak.exp(inval,.outval)
GTM>

Example : For preallocation:

% echo $GTMXC_extcall
/usr/joe/extcall.xc
% cat extcall.xc
/usr/lib/extcall.sl
prealloc: void gtm_pre_alloc_a(O:gtm_char_t *[12])
% cat extcall.c
#include <stdio.h>
#include <string.h>
#include "gtmxc_types.h"
void gtm_pre_alloc_a (int count, char *arg_prealloca)
{
    strcpy(arg_prealloca, "New Message");
    return;
}

Example : for call-back mechanism

% echo $GTMXC 
/usr/joe/callback.xc 
% cat /usr/joe/callback.xc 
$MYLIB/callback.sl 
init:     void   init_callbacks() 
tstslp:  void   tst_sleep(I:gtm_long_t) 
strtmr: void   start_timer(I:gtm_long_t, I:gtm_long_t) 
% cat /usr/joe/callback.c 
#include <stdio.h> 
#include <stdlib.h> 
 
#include "gtmxc_types.h" 
 
void **functable; 
void (*sleep_uninterrupted)(int ); 
void (*sleep_interrupted)(int ); 
void (*setup_timer)(int , int , void (*)() , int , char *); 
void (*cancel_timer)(int ); 
void* (*malloc_fn)(int); 
void (*free_fn)(void*); 
 
void  init_callbacks (int count) 
{ 
   char *start_address; 
 
   start_address = (char *)getenv("GTM_CALLIN_START"); 
 
   if (start_address == (char *)0) 
   { 
           fprintf(stderr,"GTM_CALLIN_START is not set\n"); 
      return; 
   } 
   functable = (void **)atoi(start_address); 
   if (functable == (void **)0) 
   { 
     perror("atoi : "); 
     fprintf(stderr,"addresses defined by GTM_CALLIN_START not a number\n"); 
     return; 
   } 
   sleep_uninterrupted = (void (*)(int )) functable[0]; 
   sleep_interrupted = (void (*)(int )) functable[1]; 
   setup_timer = (void (*)(int , int, void (*)(), int, char *)) functable[2]; 
   cancel_timer = (void (*)(int )) functable[3]; 
 
   malloc_fn = (void* (*)(int)) functable[4]; 
   free_fn = (void (*)(void*)) functable[5]; 
 
   return; 
} 
 
void  sleep (int count, int time) 
{ 
   (*sleep_uninterrupted)(time); 
} 
 
void timer_handler () 
{ 
   fprintf(stderr,"Timer Handler called\n"); 
   /* Do something */ 
} 
 
void  start_timer (int count, int time_to_int, int time_to_sleep) 
{ 
   (*setup_timer)((int )start_timer, time_to_int, timer_handler, 0, 0); 
   return; 
} 
void* xmalloc (int count) 
{   
return (*malloc_fn)(count); 
} 
 
void  xfree(void* ptr) 
{ 
   (*free_fn)(ptr); 
} 

Example:gtm_malloc/gtm_free callbacks using gtm_pointertofunc_t

% echo $GTMXC
/usr/joe/callback.xc
% cat /usr/joe/callback.xc
/usr/lib/callback.sl
init: void init_callbacks(I:gtm_pointertofunc_t, I:gtm_pointertofunc_t)
% gtm
GTM> do &.init(4,5)
GTM>
% cat /usr/joe/callback.c
#include <stdio.h>
#include <stdlib.h>
#include "gtmxc_types.h"
void* (*malloc_fn)(int);
void (*free_fn)(void*);
void init_callbacks(int count, void* (*m)(int), void (*f)(void*))
{
    malloc_fn = m;
    free_fn = f;
}
loading table of contents...