Skip to content
74 changes: 70 additions & 4 deletions tdishr/TdiExtFunction.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,17 @@ static void tmp_cleanup(void *tmp_in)
for (; --tmp->n >= 0;)
MdsFree1Dx(&tmp->a[tmp->n], NULL);
}

// TDI's EXT_FUNCTION is used to execute *.fun files, but doesn't execute functions in external libraries.
int Tdi1ExtFunction(opcode_t opcode __attribute__((unused)), int narg,
struct descriptor *list[], struct descriptor_xd *out_ptr)
{
int status;
struct descriptor_d image = EMPTY_D, entry = EMPTY_D;
struct descriptor_d new_entry = EMPTY_D;
FREED_ON_EXIT(&image);
FREED_ON_EXIT(&entry);
FREED_ON_EXIT(&new_entry);
status = MDSplusSUCCESS;
if (list[0])
status = TdiData(list[0], &image MDS_END_ARG);
Expand All @@ -112,7 +116,26 @@ int Tdi1ExtFunction(opcode_t opcode __attribute__((unused)), int narg,
goto done;
}

status = TdiFindImageSymbol(&image, &entry, &routine);

// (MW) TODOD: Consider deprecating the rest of this routine on all platforms.
// The EXT_FUNCTION feature to call a function in a library was broken on Ubuntu x86-64
// well before the port to Apple Silicon. Thus the Apple Silicon code added here also segfaults.
// Note that BUILD_CALL (aka ->) is used for most calls to external libraries.
// ALso, MAKE_CALL creates / executes an EXT_FUNCTION (presumably just for *.fun files).
if (STATUS_OK) {
char *c_entry = MdsDescrToCstring(&entry);
char *hash_ptr =strrchr(c_entry, '#');
if (hash_ptr == NULL) {
status = TdiFindImageSymbol(&image, &entry, &routine);
} else {
char *dup_entry = strdup(strtok(c_entry, "#"));
new_entry.length = strlen(dup_entry);
new_entry.pointer = dup_entry;
status = TdiFindImageSymbol(&image, &new_entry, &routine);
free(dup_entry);
}
free(c_entry);
}
/**********************************************
Requires: image found and routine symbol found.
**********************************************/
Expand Down Expand Up @@ -181,9 +204,51 @@ int Tdi1ExtFunction(opcode_t opcode __attribute__((unused)), int narg,
*************************/
if (STATUS_OK)
{
struct descriptor_s out = {sizeof(void *), DTYPE_POINTER, CLASS_S,
LibCallg(&new[0], routine)};
MdsCopyDxXd((struct descriptor *)&out, out_ptr);

#ifdef MDSPLUS_USE_FFI
char *c_entry = MdsDescrToCstring(&entry);
char *hash_ptr = strrchr(c_entry, '#');
int bypass_ffi = TRUE;
int num_fixed_args = 0;
if (hash_ptr != NULL) {
hash_ptr++;
num_fixed_args = atoi(hash_ptr);
}
if (num_fixed_args != 0) {
bypass_ffi = FALSE;
}
free(c_entry);
#else
int bypass_ffi = TRUE; // for Linux, Windows, and MacOS(Intel)
int num_fixed_args = 0;
#endif

if (bypass_ffi) {
struct descriptor_s out = {sizeof(void *), DTYPE_POINTER, CLASS_S, LibCallg(&new[0], (routine))};
MdsCopyDxXd((struct descriptor *)&out, out_ptr);

// Depending on the external function being called, additional "case" clauses might be required.
// Use of TRUE is because case must start with a statement.
// Struct declaration can't be declared here because it would evaluate the LibCallg*() prematurely.
// (MW) TODO: If it is decided to implement this WIP, then this code needs to be refactored for clarity,
// and edge cases need to be handled.
} else {
switch(num_fixed_args) {
#ifdef MDSPLUS_USE_FFI
case 1:
TRUE;
// Is MDS_FFI_RTN_POINTER correct here? Chose that because the descriptor is DTYPE_POINTER.
struct descriptor_s out1 = {sizeof(void *), DTYPE_POINTER, CLASS_S, LibCallgFfi(&new[0], (routine), 1, MDS_FFI_RTN_POINTER)};
MdsCopyDxXd((struct descriptor *)&out1, out_ptr);
break;
#endif
default:
TRUE;
struct descriptor_s out = {sizeof(void *), DTYPE_POINTER, CLASS_S, LibCallg(&new[0], (routine))};
MdsCopyDxXd((struct descriptor *)&out, out_ptr);
break;
}
}
}
pthread_cleanup_pop(1);
}
Expand All @@ -192,5 +257,6 @@ int Tdi1ExtFunction(opcode_t opcode __attribute__((unused)), int narg,
done:;
FREED_NOW(&entry);
FREED_NOW(&image);
FREED_NOW(&new_entry);
return status;
}