5

Linux シリアル ポートで low_latency tty モードを使用しても安全ですか? tty_flip_buffer_push関数は、「port->low_latency が設定されている場合、IRQ コンテキストから呼び出してはならない」と文書化されています。それにもかかわらず、多くの低レベルのシリアル ポート ドライバーは、フラグが設定されているかどうかに関係なく、ISR から呼び出します。たとえば、mpc52xx ドライバーは、FIFO から読み取るたびに無条件にフリップ バッファーを呼び出します。

ISR の低レイテンシ フリップ バッファーの結果として、ライン ディシプリン ドライバーが IRQ コンテキスト内に入力されます。私の目標は、高速 mpc52xx シリアル ポートから読み取り、レイテンシを 1 ミリ秒以下にすることです。low_latency を設定するとレイテンシーの目標が達成されますが、tty_flip_buffer_push の文書化された前提条件にも違反します。

4

2 に答える 2

6

この質問は、2011 年 8 月 19 日金曜日の linux-serial で尋ねられました。

いいえ、低遅延は一般的に安全ではありません。

ただし、特定のケースでは 3.10.5low_latencyが安全です。

上記のコメントは次のとおりtty_flip_buffer_pushです。

「port->low_latency が設定されている場合、この関数を IRQ コンテキストから呼び出してはなりません。」

ただし、コード (3.10.5、drivers/tty/tty_buffer.c) はこれと矛盾しています。

void tty_flip_buffer_push(struct tty_port *port)
{
    struct tty_bufhead *buf = &port->buf;
    unsigned long flags;

    spin_lock_irqsave(&buf->lock, flags);
    if (buf->tail != NULL)
            buf->tail->commit = buf->tail->used;
    spin_unlock_irqrestore(&buf->lock, flags);

    if (port->low_latency)
            flush_to_ldisc(&buf->work);
    else
            schedule_work(&buf->work);
}
EXPORT_SYMBOL(tty_flip_buffer_push);

spin_lock_irqsave/を使用するとspin_unlock_irqrestore、このコードを割り込みコンテキストから安全に呼び出すことができます。

のテストがあり、low_latency設定されている場合flush_to_ldiscは直接呼び出されます。これにより、割り込み処理が長くなるという代償を払って、フリップ バッファーがすぐにライン ディシプリンにフラッシュされます。このflush_to_ldiscルーチンは、割り込みコンテキストで安全に使用できるようにコーディングされています。以前のバージョンは安全ではなかったと思います。

が設定されていない場合low_latencyは、が呼び出されます。呼び出しは、割り込みコンテキストで「上半分」から「下半分」のハンドラーを呼び出す古典的な方法です。これにより、次のクロックティックで「下半分」ハンドラーから呼び出されます。schedule_workschedule_workflush_to_ldisc

もう少し詳しく見てみると、コメントとテストの両方が Alan Cox の元の.com のe0495736コミットにあるようですtty_buffer.c。このコミットは以前のコードを書き直したものなので、一度はテストがなかったようです。テストを追加し、flush_to_ldisc割り込みセーフに修正した人は誰でも、わざわざコメントを修正しませんでした。

したがって、コメントではなく常にコードを信じてください。

ただし、3.12-rc* の同じコード (2013 年 10 月 23 日現在) では、flush_to_ldisc の spin_lock_irqsave が削除され、mutex_locks が追加されたときに、問題が再び発生したようです。つまり、serial_struct フラグで UPF_LOW_LATENCY を設定し、TIOCSSERIAL ioctl を呼び出すと、再び「アトミックなスケジュール」が発生します。

メンテナからの最新の更新は次のとおりです。

On 10/19/2013 07:16 PM, Jonathan Ben Avraham wrote:
> Hi Peter,
> "tty_flip_buffer_push" is called from IRQ handlers in most drivers/tty/serial UART drivers.
> 
> "tty_flip_buffer_push" calls "flush_to_ldisc" if low_latency is set.
> "flush_to_ldisc" calls "mutex_lock" in 3.12-rc5, which cannot be used in interrupt context.
> 
> Does this mean that setting "low_latency" cannot be used safely in 3.12-rc5?

Yes, I broke low_latency.

Part of the problem is that the 3.11- use of low_latency was unsafe; too many shared
data areas were simply accessed without appropriate safeguards.

I'm working on fixing it but probably won't make it for 3.12 final.

Regards,
Peter Hurley

low_latencyしたがって、カーネルをサポートしているバージョンから変更しないことが確実でない限り、依存するべきではないようです。


更新: 2014 年 2 月 18 日、カーネル 3.13.2

スタニスワフ・グルシュカは次のように書いています。

Hi,

setserial has low_latency option which should minimize receive latency
(scheduler delay). AFAICT it is used if someone talk to external device
via RS-485/RS-232 and need to have quick requests and responses . On
kernel this feature was implemented by direct tty processing from
interrupt context:

void tty_flip_buffer_push(struct tty_port *port)
{
    struct tty_bufhead *buf = &port->buf;

    buf->tail->commit = buf->tail->used;

    if (port->low_latency)
            flush_to_ldisc(&buf->work);
    else
            schedule_work(&buf->work);
} 

But after 3.12 tty locking changes, calling flush_to_ldisc() from
interrupt context is a bug (we got scheduling while atomic bug report
here: https://bugzilla.redhat.com/show_bug.cgi?id=1065087 )

I'm not sure how this should be solved. After Peter get rid all of those
race condition in tty layer, we probably don't want go back to use
spin_lock's there. Maybe we can create WQ_HIGHPRI workqueue and schedule
flush_to_ldisc() work there. Or perhaps users that need to low latency,
should switch to thread irq and prioritize serial irq to meat
retirements. Anyway setserial low_latency is now broken and all who use
this feature in the past can not do this any longer on 3.12+ kernels.

Thoughts ?

Stanislaw
于 2013-10-19T20:07:37.193 に答える