DragonFly - The Port/Messaging Model ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ The Port/Messaging Model ポート/メッセージモデル DragonFly will have a lightweight port/messaging API to go along with its lightweight kernel threads. The port/messaging API is very simple in concept; You construct a message, you send it to a target port, and at some point later you wait for a reply on your reply port. On this simple abstraction, we intend to build a high level of capability and sophistication. To understand the capabilities of the messaging system, you must first understand how a message is dispatched. It basically works like this: DragonFly は LWKT に同調する軽量なポート/メッセージ API を備える予定です。 ポート/メッセージ API の概念は非常に単純です。まずメッセージを組み立て、目 標となるポートへ送り、あとで自分の応答ポートに返事が来るのを待つというもの です。この単純な概念にもとづいて、高度な機能を構築し、洗練化を行います。こ のメッセージングシステムの機能を理解するには、まずメッセージがどのように送 信されるのかを理解する必要があります。基本的には以下のように動作します: fubar() { FuMsg msg; initFuMsg(&msg, replyPort, ...); error = targetPort->mp_SendMsg(&msg); if (error == EASYNC) { /* now or at some later time, or wait on reply port */ error = waitMsg(&msg); } } The messaging API will wrap this basic mechanism into synchronous and asynchronous messaging functions. For example, lwkt_domsg() will send a message synchronously and wait for a reply. It will set a flag to hint to the target port that the message will be blocked on synchronously and if the target port returns EASYNC, lwkt_domsg() will block. Likewise lwkt_sendmsg() would send a message asynchronously, but if the target port returns a synchronous error code (i.e. anything not EASYNC) lwkt_sendmsg() will manually queue the now complete message on the reply port itself. メッセージ API はこの基本的は構造を同期/非同期メッセージ関数に内包します。 lwkt_domsg() はメッセージを同期的に送り、返答を待ちます。この関数は目標ポ ートにヒントを与えるためのフラグをセットします。それはメッセージが同期的に ブロックされることを示すもので、目標ポートが EASYNC を返した場合 lwkt_domsg() はブロックします。lwkt_sendmsg() はメッセージを非同期的に送り ますが、目標ポートが同期的なエラーコード(つまり EASYNC 以外全て)を返した場 合、lwkt_sendmsg() はもう完了したメッセージを返答ポート自身のキューに手動 で入れます。 As you may have guessed, the target port's mp_SendMsg() function has total control over how it deals with the message. Regardless of any hints passed to it in the messaging flags, the target port can decide to act on the message synchronously (in the context of the caller) and return, or it may decide to queue the message and return EASYNC. Messaging operations generally should not 'block' from the point of view of the initiator. That is, the target port should not try to run the message synchronously if doing so would cause it to block. Instead, it should queue it to its own thread (or to the message queue conveniently embedded in the target port structure itself) and return EASYNC. 推測できると思いますが、目標ポートの mp_SendMsg() 関数はメッセージをどう扱 うかを完全に制御します。メッセージフラグによって渡されたヒントがどのような ものであっても、目標ポートはメッセージに対して(呼び元から見て)同期的にふる まって応答することも、メッセージをキューに入れて EASYNC を返すこともできま す。一般的にメッセージ処理は発信者から見て「ブロック」すべきではありません。 つまり、メッセージを同期的に処理することがブロックにつながるのであれば目標 ポートは同期的に処理してはいけないということです。そのかわりに、自身のスレ ッドのキュー(目標ポートの構造体に、便利なように埋め込んであるメッセージキ ュー)に入れて、 EASYNC を返すようにします。 A target port might act on a message synchronously for any number of reasons. It is in fact precisely the mp_sendMsg() function for the target port which deals with per-cpu caches and opportunistic locking such as try_mplock() in order to deal with the request without having to resort to more expensive queueing / switching. 目標ポートは幾つかの理由によりメッセージに対し同期的に振舞うかもしれません。 実際に 目標ポートのための mp_sendMsg() 関数は、より高価なキューイングやス イッチングを用いることなしに要求を処理するために、 CPU ごとのキャッシュや try_mplock() のような[日和見的な]ロッキング を利用することで、まさにそう振 舞います。 The key thing to remember here is that our best case optimization is direct execution by mp_SendMsg() with virtually no more overhead then a simple subroutine call would otherwise entail. No queueing, no messing around with the reply port... If a message can be acted upon synchronously, then we are talking about an extremely inexpensive operation. It is this key feature that allows us to use a messaging interface by design without having to worry about performance issues. We are explicitly NOT employing the type of sophistication that, say, Mach uses. We are not trying to track memory mappings or pointers or anything like that, at least not in the low level messaging interface. User <->Kernel messaging interfaces simply employ mp_SendMsg() function vectors which do the appropriate translation, so as far as the sender and recipient are concerned the message will be local to their VM context. ここで覚えておくべき重要なことは、もっともよい最適化とは mp_SendMsg() によ る直接の実行で、単純なサブルーチン呼出しの他には実質的にオーバヘッドを伴わ ないことです(訳注: no more〜thenは Dillon のいつもの釣りね)。キュー処理も せず、応答ポートをいじることもなく、ということです。もしメッセージを同期的 に扱ってよいのであれば、これは非常にコストの低い処理ということになります。 この特徴があるからこそ、性能の問題を気にせずにメッセージングインタフェース を意図して使うことができるのです。私達はたとえば Mach で用いているような種 類の洗練手法を使うことはあえてしません。少なくとも低レベルなメッセージイン タフェイスでは、メモリマップやポインタの追跡といったことをしません。ユーザ ⇔カーネル間のメッセージインタフェイスは単純に mp_SendMsg() の関数ベクタを 用い、それによって適切な変換をします。そうすることで、送信側と受信側に関し ては、メッセージがそれらの VM コンテキストに対しローカルになります(訳注: 局所性を持つということ)。