関数のアドレスを別のプロトタイプにキャストし、結果のポインターを介して呼び出すことにより、互換性のないプロトタイプで関数を呼び出すことは違法です。
void *my_callback(void *arg) { ... }
void (*broken)(void *) = (void (*)(void *)) my_callback;
broken(some_arg); // incorrect, my_callback returns a `void *`
あなたができることは、その戻り値makecontext
を呼び出して無視するあなた自身のコールバックに渡すことです。thread_func
別の関数を呼び出すためだけに機能する小さな関数は、トランポリンと呼ばれることもあります。
/* return type is compatible with the prototype of the callback received
by makecontext; simply calls the real callback */
static void trampoline(int cb, int arg)
{
void *(*real_cb)(void *) = (void *(*)(void *)) cb;
void *real_arg = arg;
real_cb(real_arg);
}
int my_pthread_create(void *(*cb)(void *), void *arg)
{
ucontext_t *ucp;
...
/* For brevity treating `void *` as the same size as `int` -
DO NOT USE AS-IS.
makecontext exposes an annoyingly inconvenient API that only
accepts int arguments; correct code would deconstruct each
pointer into two ints (on architectures where pointer is
larger than int) and reconstruct them in the trampoline. */
makecontext(ucp, trampoline, 2, (int) cb, (int) arg);
...
}
ボーナスポイントについては、トランポリンを変更して、コールバック関数によって返された値をスタックに格納しvoid *
、同等の値をpthread_join()
取得することができます。