Skip to content
Advertisement

Why makecontext’s func only accepts integer arguments

The man page for makecontext states that the arguments after argc should be integer(int) only:

…the function func is called, and passed the series of integer (int) arguments that follow argc

If we look at pthread_create or clone system call, they have one void* argument which is to passed to the func, and a pointer of struct can contain any number of data the user wishes to have, and these two function don’t need to use va_args either. So my question is why makecontext does not use this kind of technique, i.e., use a void pointer, instead of argc and va_args?

Advertisement

Answer

This was a design flaw that led to the demise/removal of makecontext. See the rational text for the last version of POSIX it was included in:

http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.html

With the incorporation of the ISO/IEC 9899:1999 standard into this specification it was found that the ISO C standard (Subclause 6.11.6) specifies that the use of function declarators with empty parentheses is an obsolescent feature. Therefore, using the function prototype:

void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);

is making use of an obsolescent feature of the ISO C standard. Therefore, a strictly conforming POSIX application cannot use this form. Therefore, use of getcontext(), makecontext(), and swapcontext() is marked obsolescent.

There is no way in the ISO C standard to specify a non-obsolescent function prototype indicating that a function will be called with an arbitrary number (including zero) of arguments of arbitrary types (including integers, pointers to data, pointers to functions, and composite types).

Replacing makecontext() with a number of ISO C standard-compatible functions handing various numbers and types of arguments would have forced all existing uses of makecontext() to be rewritten for little or no gain. There are very few applications today that use the *context() routines. Those that do use them are almost always using them to implement co-routines. By maintaining the XSH, Issue 5 specification for makecontext(), existing applications will continue to work, although they won’t be able to be classified as strictly conforming applications.

There is no way in the ISO C standard (without using obsolescent behavior) to specify functionality that was standard, strictly conforming behavior in the XSH, Issue 5 specification using the ISO C standard. Threads can be used to implement the functionality provided by makecontext(), getcontext(), and swapcontext() but they are more complex to use. It was felt inventing new ISO C standard-compatible interfaces that describe what can be done with the XSH, Issue 5 functions and then converting applications to use them would cause more difficulty than just converting applications that use them to use threads instead.

Note that, in order for the implementation of makecontext to actually call func, it has to know how to setup a stack frame for entry to a function with the right number and type of arguments. If all arguments are required to have the same type (int), it’s possible to know that just from the number, argc. If they were allowed to have different types, the caller would somehow have to pass a specification of the types as an argument to makecontext; a simple count is not sufficient to know how to copy them from the va_list received by makecontext to the stack frame for entry to func.

Of course makecontext‘s func should have just taken a single void *, and then the problem would never have arisen. But it didn’t.

Advertisement