継続

継続インタフェースは Traffic Server の基本的なコールバックメカニズムです。 Continuations は不明瞭なデータ型 TSCont のインスタンスです。基本的な形式では、継続はハンドラー関数とミューテックスを表現します。

この章では下記のトピックをカバーします。

ミューテックスとデータ

下記のどれかを行う際、継続はミューテックスを伴って生成されなければなりません。

  • TSHttpHookAdd もしくは TSHttpSsnHookAdd で)大域的に HTTP フックに登録され、 TSContDataSet/Get を使用する。

  • TSHttpTxnHookAdd で)局所的に登録されるが、複数のトランザクションが TSContDataSet/Get を使用する。

  • TSCacheXXX, TSNetXXX, TSHostLookup, もしくは TSContScheduleOnPool API を使用する。

アクティベートされる前に、呼び出し元は継続のミューテックスを掴まなければなりません。この要求は継続のハンドラー関数がそのデータに安全にアクセスし、同時に複数の動作中の呼び出し元が発生するのを防ぐことができるようにするためです。(使用方法については サンプルプロトコルについて を見てください。)ミューテックスに守られるデータは TSContDataSet により継続に関連付けられる任意の大域、または継続のデータです。これは継続ハンドラー関数に作成されるローカルデータを含みません。関連付けられるデータ構造とミューテックスと共に生成される継続の典型的な例は、サンプルプロトコルプラグイン内で生成されるトランザクションステートマシンです。( トランザクションステートマシンを実装する方法の一つ を見てください)

再入可能な呼び出しは、継続を引数として渡した際に、 API の関数呼び出しとして同じスタックトレース内で API を呼び出し可能にします。例えば TSCacheRead (contp, mykey) を呼び出す場合、 contp のハンドラーは直接呼び出され、その後 TSCacheRead を返すことが可能です。

下記を含む問題を起こす可能性がある注意事項:

  • 継続はそれに関連付いたデータ( TSContDataGet )を持ちます。

  • 再入可能呼び出しは自身を継続として再入可能 API に渡します。この場合、継続は再入可能 API を呼び出した後にデータへのアクセスを試みるべきではありません。この理由は、 API によって送られるイベントを処理する継続のハンドラー内のコード部分によってデータが変更されているかもしれないからです。解放されたデータへのアクセスを避けるため、再入可能呼び出しの後は常に return することを推奨します。

下記は例とその説明です。

continuation_handler (TSCont contp, TSEvent event, void *edata) {
    switch (event) {
        case event1:
            TSReentrantCall (contp);
            /* Return right away after this call */
            break;
        case event2:
            TSContDestroy (contp);
            break;
    }
}

上の例は、まず継続が event1 を伴ってコールバックされる事を想定します。その後 event2 を受け取るために継続をスケジュールする再入可能呼び出しを行います。この呼び出しは再入可能なので、プロセッサーはすぐに event2 を伴って継続をコールバックし、継続は破棄されます。もし再入可能呼び出し後に継続かそのメンバーのどれかにアクセスを試みたら、解放されたデータへアクセスすることになる可能性があります。解放されたデータへのアクセスを避けるため、再入可能呼び出し後は継続やそのメンバーのいずれかへのアクセスをせず、単にハンドラーを抜けてください。

注意: ほとんどの HTTP トランザクションプラグインの継続は null でないミューテックスを必要としません。なぜならそれらは HTTP トランザクションの処理内で呼び出されるので、トランザクションのミューテックスを持っているためです。

It is also possible to specify a continuation's mutex as nullptr. This should be done only when registering a continuation to a global hook, by a call to TSHttpHookAdd. In this case, the continuation can be called simultaneously by different instances of HTTP SM running on different threads. Having a mutex here would slow and/or hinder Traffic Server performance, since all the threads will try to lock the same mutex. The drawback of not having a mutex is that such a continuation cannot have data associated with it (i.e., TSContDataGet/Set cannot be used).

When using a nullptr mutex it is dangerous to access the continuation's data, but usually continuations with nullptr mutexes have no data associated with them anyway. An example of such a continuation is one that gets called back every time an HTTP request is read, and then determines from the request alone if the request should go through or be rejected. An HTTP transaction gives its continuation data to the contp.