С РПЦ без заглушек - PullRequest
       9

С РПЦ без заглушек

2 голосов
/ 09 апреля 2009

У меня есть эта программа, которую я хочу, чтобы другие процессы могли вызывать функции (через сокеты Unix). Протокол сообщений очень прост: имя функции, сигнатура функции и буфер (char *), который содержит параметры.

Когда модуль в моей программе хочет разрешить доступ к функции, он регистрирует имя и подпись в библиотеке. Проблема, с которой я сталкиваюсь, заключается в физическом вызове функции после поступления запроса. Я посмотрел на RPC и java RMI-подобные библиотеки, но для этого требуется, чтобы я генерировал заглушки для переноса вызовов. Система, над которой я работаю, очень динамична, и мне также приходится взаимодействовать с кодом других людей, который я не могу изменить.

Таким образом, в принципе, функция может выглядеть следующим образом:

int somefunc(int someparam, double another)
{
    return 1234;
}

сейчас я регистрируюсь в библиотеке:

//           func ptr   name       signature
REG_FUNCTION(somefunc, "somefunc", "i:id");

Когда приходит запрос, я делаю некоторую проверку на наличие ошибок, и после подтверждения я хочу вызвать функцию. Итак, у меня есть переменные:

void * funcptr = (the requested function);
char * sig = (the function signature);
char * params = (a buffer of function parameters);
//note that the params buffer can hold data types of arbitrary lengths

Как я могу вызвать функцию с параметрами в C?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 09 апреля 2009

Я не думаю, что это вообще полностью разрешимо, используя только C. Вы не знаете, например, соглашение о вызовах, используемое целевой функцией. Существует риск того, что вы в конечном итоге «обманете» компилятор или, по крайней мере, будете вынуждены его угадать. Что, если компилятор решил построить зарегистрированную функцию, используя аргументы, переданные в регистрах, возможно, из-за некоторой настройки оптимизации (или что, если она была построена с другим компилятором?).

Также в общем случае нет способа выразить в C, что вы хотите вызвать функцию с заданным набором аргументов, и что значения для аргументов необходимо распаковать из буфера случайных байтов.

Вы могли бы сделать что-то ужасное, как это:

enum { VOID_INT, VOID_INT_DOUBLE, VOID_DOUBLE_INT, ... } Signature;

void do_call(const void *userfunction, const void *args, Signature sig)
{
  switch(signature)
  {
    case VOID_INT:
    {
      int x = *(int *) args;
      void (*f)(int) = userfunction;
      f(x);
      break;
    }
    case VOID_INT_DOUBLE:
    ...
  }
}

Но совершенно очевидно, что это не живет на том же континенте, что и масштабируемость. Конечно, вы можете автоматически сгенерировать этот код для некоторого разумного набора типов возвращаемых данных и типов аргументов. Вы бы все еще были немного в дураках для приведения указателей функций к / из void *, но это может быть приемлемо. Вы все равно всегда рискуете, что кто-то вручит вам подпись, для которой у вас нет предварительно сгенерированного кода.

0 голосов
/ 23 ноября 2011

Выезд libffi . Эта библиотека позволяет вызывать функцию с набором параметров, указанных во время выполнения.

...