Search code examples
cprocessstackpthreads

Function that can execute every other function


I'm studying threads in university and I would like to make a library in C that does similar things to pthread but using processes and then compare the performances of both.

In other words I would like to make function like:

function execute_function(func_ptr, args)

Where func_ptr is a generic pointer to function like void* (*f)() and args...well I don't know...
The problem here is obviously that I don't know inside of execute_function the number and types of the arguments of the function pointed.

I wondered if there was a way to "manually" allocate arguments on the stack and then call the function, in this case I would add an argument for the total argument size.

The only solution I came up with is to wrap the function pointed by func_ptr with a function that takes as single parameter a valist, this function would then "unwrap" the valist as the wrapped function would expect, but it seems far from how pthread_create works.

Do someone have an idea?


Solution

  • pthread_create receives a function with exactly void *(void *) signature and when executing the thread it passes the 4th argument as the function argument.

    To call your own function, typically you create a structure with your arguments, pack your arguments into the structure and just use the structure inside your function.

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    struct yourargs {
      int arg1;
      char arg2;
    };
    void *yourfunction(struct yourargs *this) { 
        printf("%d %c\n", this->arg1, this->arg2);
        return 0;
    }
    
    
    void *yourfunction_trampoline(void *cookie) {
        struct yourargs this = *(struct yourargs *)cookie;
        free(cookie);
        return yourfunction(&this);
    }
    
    int main() {
        struct yourargs *a = malloc(sizeof(*a));
        *a = (struct yourargs){1, 'a'};
        pthread_t p;
        pthread_create(&p, 0, yourfunction_trampoline, a);
        pthread_join(p, 0);
    }
    

    You could unpack the structure, but it's easier to just have it together anyway.

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void *yourfunction(int arg1, char arg2) { 
        printf("%d %c\n", arg1, arg2);
        return 0;
    }
    
    struct yourargs {
      int arg1;
      char arg2;
    };
    void *yourfunction_trampoline(void *cookie) {
        struct yourargs arg = *(struct yourargs *)cookie;
        free(cookie);
        return yourfunction(arg.arg1, arg.arg2);
    }
    
    int main() {
        struct yourargs *a = malloc(sizeof(*a));
        *a = (struct yourargs){1, 'a'};
        pthread_t p;
        pthread_create(&p, 0, yourfunction_trampoline, a);
        pthread_join(p, 0);
    }
    

    Between the real function and actual function, typically you add a trampoline function with the signature void *(void *) in which to cast or unpack the structure. As I understand, you are searching for that trampoline function.

    Now, bottom line, you "want" std::thread(yourfunction, 1, 'a') in C. That is not possible. There are no lambdas, objects, templates, constructors nor destructors in C programming language. You have to write, type it out, all the names and objects and types you are going to use and free and allocate memory yourself. You can hide your code behind intricate macros, in which case the code becomes a burden to maintain. You could also use extensions to C programming language, like GCC nested functions or "blocks" lambdas in clang or OpenMP, but they are extensions. In C, you type it out, write the trampoline function, allocate arguments, unpack the structure.