私は小さな作業用プラグイン サーバーを作成しました。プラグインは共有オブジェクトを使用して実装されます。共有オブジェクトは実行時に(header ).so
の呼び出しによって「サーバー」に手動でロードされます。dlopen
<dlfcn.h>
すべての共有オブジェクト プラグインは同じインターフェースを持っています。
extern "C" void* do_something() {
return SharedAllocator<T>{}.allocate(...); // new T
}
extern "C" size_t id = ...; // unique
- 基本的に
do_something
、呼び出し元が解放すると予想されるヒープメモリへのポインタを返します。 id
は単に ごとに一意の識別子.so
です。T
は、それぞれに固有の構造体.so
です。戻り値の型が同じものもあれば、そうでないものもあります。ここでのポイントは、sizeof(T)
具体.so
的です。
.so
サーバーは、バイナリのシンボルの動的な読み込みと読み取りを担当します。すべての.so
プラグインは、サーバー バイナリで定義されたメソッドを介して相互に呼び出すことができますdo_something_proxy
。これは、呼び出し元と呼び出し先の間の接着剤として機能します。
extern "C" void* do_something_proxy(size_t id) {
// find the requested handle
auto handle = some_so_map.find(id)->second;
// call the handle's `do_something`
void* something_done = handle.do_something();
// forward the result
return something_done;
}
物事を少し単純化するために、プロキシが実行されたときに一連の呼び出しを使用して埋められsome_so_map
たプレーンであるとしましょう。std::unordered_map<size_t, so_handle_t>
dlopen
私の問題は、すべての呼び出し元がコンパイル時にdo_something_proxy
知っていることです。T
前に述べたように、T
呼び出しサイトごとに異なる場合があります。ただし、任意の呼び出しサイトでは変更されT
ません。
参考までに、すべての呼び出し元が使用する定義を次に示します。
template <typename T, size_t id>
T* typed_do_soemthing_proxy() {
// simple cast of the proxy
return reinterpret_cast<T*>(do_soemthing_proxy(id));
}
つまり、do_something_proxy
任意のプラグインid
は常に同じ戻り値の型を持ちます。
プロキシがない場合は、テンプレートdo_soemthing_proxy
化して渡すT
か、std::array<int8_t, N>
with を使用するだけで、呼び出しがスタックに移動されたときにsizeof(T) == N
割り当てられた不要なメモリがスライスされないようにすることができます。ただし、プロキシは、コンパイル時にすべての可能な戻り値の型を認識することはできず、無数のバージョンの をエクスポートします。T
do_something_proxy
do_something_proxy
だから私の質問はdo_soemthing_proxy
、そのスタックに有効なサイズを割り当てる方法はありますかT
(つまりalloca
、スタック割り当ての他の形式を使用するか)?
私が知る限り、要求されたプラグインの関数から単一の値しか受け取ることができないため、alloca
ここでは機能していないようです。割り当てるサイズと、割り当てられたメモリにコピーするバイトの両方を同時に受け取ります。間に「押しつぶす」ことができれば...do_soemthing_proxy
do_something
do_soemthing_proxy
alloca
std::array<int8_t, N>
の値に 256 または 1024 を使用して、スタックに一定量のメモリを割り当てることができることを知っていますN
。ただし、このソリューションは少し汚れています。あるスタックフレームから別のスタックフレームにデータを不必要にコピーし、プラグインが返すことができるデータの量を制限します。さらに、(私はまだこのソリューションのベンチマークを行っていませんが) コンパイラが動的境界を越えてコピーを削除できない限り、1024 バイトをコピーすることは、つまりsizeof(std::string)
バイトをコピーすることよりも多くの作業であると想定します。
理想的な世界では、do_soemthing_proxy
これを RAII で処理する構造体を返す必要があると思います。const std::any
必要に応じて、スタック割り当てされた A。これは可能ですか?
これが c++ 内でまったく不可能な場合、スタックまたはベース ポインターを手動でハイジャックすることによって、アセンブリで移植可能な方法でこの動作を実現することは可能でしょうか?
ありがとう。