Search code examples
cucontext

How do I pass arguments to makecontext()'s start routine?


I'd like to pass 3 arguments to thread_routine_handler like this:

makecontext(&th->context, thread_routine_handler, 3, th, start_routine, arg);

but I don't know how to read them properly. It returns the warning:

warning: passing argument 2 of ‘makecontext’ from incompatible pointer type [-Wincompatible-pointer-type void (*)(thread_t *, void (*)(), void *) {aka void (*)(struct thread *, void (*)(), void *)}

my callback routine is defined like this:

void thread_routine_handler(thread_t *th, start_routine_t start_routine, void *arg_routine)
{ ... }

It's working but I'm afraid of some UB behavior. The 2 argument of makecontext does expect a function taking no arguments. How am I supposed to read them? even with va_start() etc I do need at least one argument (argc) or am I missing something? what's the proper way to do that?

UPDATE

start_routine_t is typedef void (*start_routine_t)();


Solution

  • The expected type for the second parameter to makecontext() is void (*)(). As the diagnostic message indicates, the type of the argument you are passing is void (*)(thread_t *, void (*)(), void *). These are not "compatible" types in the sense in which the C language spec uses that term, on account of the latter being declared with a function prototype and the former not.

    However, given the particular types of the parameters to your thread_routine_handler() function, it is possible to call that via a pointer of type void (*)(), provided that the actual arguments are of the correct types. The best available solution is to apply an appropriate typecast to the makecontext() argument. If the actual arguments are not of exactly the correct types, then you should cast those, too. Thus, in full generailty:

    makecontext(&th->context, (void (*)()) thread_routine_handler,
            3, (thread_t *) th, (start_routine_t) start_routine, (void *) arg);
    

    You can omit any of those casts that convert values to (exactly) the types they already have.

    But that's largely irrelevant here, because you have an issue with the other arguments that your compiler is not diagnosing (understandably). The variable arguments to makecontext(), those that are forwarded to the specified function, are required to all be of type int (thanks, @user253751). Their number can vary, but not their types. I overlooked that in the original version of this answer.

    It follows that thread_routine_handler() can accept any number of arguments compatible with type int or unsigned int, but none of any other type. You will still need to cast the pointer to the start function, as already described, but you cannot safely use the particular function you are trying to use. Possibly you can set up a global, dynamically-allocated table of the th, start_routine, and arg triples, and pass an index into that.