2016-10-27 18 views
3

Linuxマシンでシミュレートする必要がある組み込みOS関数がいくつかあります。私が取るように指示されたアプローチは、組み込みOS関数をオーバーロードしてPOSIXスレッドの周りにラップすることで、単体テストなどの組み込みOS機能をLinuxマシンが処理できるようにすることです。新しいスレッドを作成するための関数ポインタtypedefを

組み込みOSの機能は次のとおりです。(void * (*)(void *)はコンパイラが、それは期待しています私に語ったものです)

OSCreateTask(OStypeTFP functionPointer, OSTypeTcbP taskId, OStypePrio priority)

私はpthread_createを期待void関数ポインタにそのOStypeTFPタイプを変換する必要があります

は、私はそれが好きで使用することができtypedefを作成するために期待していた。

typedef void (*OStypeTFP)(void); 

// Function to run task/thread in 
void taskFunction(void) { while(1); } 

// Overloaded Embedded OS function 
void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 

    pthread_attr_init(&threadAttributes); 
    pthread_create(&thread, &threadAttributes, &tFP, NULL); 
} 

// Creates a task that runs in taskFunction 
OSCreateTask (taskFunction, id, prio); 

をコンパイラはそのに文句を言いますは、タイプvoid (**)(void)で、pthread_createが期待する場合void * (*)(void *)

何らかの形でtypecefを変更する必要がありますか?どちらも?

+0

関数は '無効*'パラメータを取り、返さなければ '無効*'あなたはより多くを読む必要が – imreal

+0

['pthread_create'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html)とおそらく一般的なスレッドに関するものです。関数と関数へのポインタだけでなく、ポインタへの減衰と、ポインタ変数でのアドレス演算子の動作についても説明します。 –

+0

関数(名前)を「オーバーロードする」とは、同じ名前で異なる引数型を持つ異なる関数を提供することです。 Cはそれをサポートしていません。 –

答えて

5

あなたはアダプタ機能を必要とする:あなたのシステムがvoid *からのキャストは、ポインタを機能させることができた場合にのみ安全であるもちろん

typedef void (*OStypeTFP)(void); 

// Function to run task/thread in 
void taskFunction(void) { while(1); } 

void *trampoline(void *arg) 
{ 
    OStypeTFP task = (OStypeTFP)arg; 
    task(); 
    return NULL; 
}  

// Overloaded Embedded OS function 
void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 

    pthread_attr_init(&threadAttrs); 
    pthread_create(&thread, &threadAttrs, trampoline, tFP); 
} 

// Creates a task that runs in taskFunction 
OSCreateTask (taskFunction, id, prio); 

。しかし、私たちはPOSIX環境にいるので、これは問題ありません。

+0

@BjornAを無視してラッパーを作成する必要があります。私の悪い。ありがとう! – Sergio

+0

ああ!私は前にこのようなことを試みましたが、新しいタスク変数を作成してからtask()を呼び出す代わりにarg()を呼び出してみました。ありがとう! – cjameston

+0

@ 2501 Cは関数ポインタとオブジェクトポインタの間の変換に_require_は必要ではありませんが、どちらもそうすることはできません。そして、 'pthread_ *' APIを指定するPOSIXでは、関数ポインタと 'void *'(特に)の間の変換が必要です。したがって、シムに渡す必要のある追加のデータがない限り、この回答は完全に良好です。 OPはエミュレートしている組み込みOSについて慎重であるため、追加データが必要かどうかはわかりません。 – zwol

3

私が正しく理解していれば、埋め込みOS上のスレッドプロシージャの署名はvoid thread_proc(void)です。一方、POSIXスレッドの場合はvoid *thread_proc(void *)です。

キャストやtypedefでこの相違点を記録することはできません。適切な戻り値を用意する必要があります。

typedef void (*OStypeTFP)(void); 
struct emu_OSCreateTask_thread_start_data 
{ 
    OStypeTFP real_thread_proc; 
    // possibly other stuff 
}; 

void *emu_OSCreateTask_shim_thread_proc (void *xctx) 
{ 
    struct emu_OSCreateTask_thread_start_data *ctx = xctx; 

    ctx->real_thread_proc(); 
    return 0; 
} 

void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 
    struct emu_OSCreateTask_thread_start_data *ctx = 
     malloc(sizeof(struct emu_OSCreateTask_thread_start_data)); 

    ctx->real_thread_proc = tFP; 

    pthread_attr_init(&threadAttributes); 
    pthread_create(&thread, &threadAttributes, 
        emu_OSCreateTask_shim_thread_proc, ctx); 
} 

注:それは無期限後にOSCreateTaskリターンよりかもしれemu_OSCreateTask_shim_thread_proc戻り、後まで生きるために必要があるのでctxは、ヒープ上に割り当てられ、かつ漏洩したあなたは、シムの機能を必要としています。あなたがエミュレートしようとしているAPIについて詳しく知りませんが、適切なときに解放できるようにどこに隠しておかなければならないのかは分かりませんが、おそらくのどこかにがあります。多分tcbPにありますか?

注2:pthread_createのコンテキストポインタ(Sergioの回答のように)に「real_thread_proc」を詰め込むのではなく、コンテキストオブジェクトを使用します。シムにもっと多くのものを必要とし、それを行うために外側の文脈からより多くのデータ。 (それvoid *にスタッフ関数ポインタにも安全なようにあなたは、POSIXシステムにしている。)

+0

私は、 'emu_OSCreateTask_shim_thread_proc()'から戻る前に 'free()' 'ctx'を実行するべきだと思います。 – Sergio

+0

@Sergio必ずしもそうではありません。 'pthread_join'に相当するまで生き残る必要があるかもしれません。 – zwol

+0

@zwolこれは、構造体にポインタをラップするときの正解です。渡されたパラメータについてpthread_joinが知られていないので、関数呼び出しが終了した後も解放されない理由はありません。作成されたスレッドがメモリを解放するのは間違いありません。 – 2501