1

私は組み込みプラットフォームに取り組んでおり、物理メモリを直接読み書きするための完全なアクセス権を持っています。

また、非対称処理にも取り組んでいます。この処理では、リアルタイム アプリケーションを Linux と同時に実行していますが、Linux からは完全に分離しています。

RT アプリから Linux コンソールにメッセージを表示したい (そしておそらく Linux から RT アプリにコマンドを送信したい)。私の現在の解決策は、RT アプリからシリアル ポートにすべてを出力することです。次に、Linux でシリアル ポートの入力を読み取ります。

これは機能しますが、RT アプリと Linux が同じ物理マシン上にあるため、不要なようです。シリアルポートがどのように機能するかを考えてみると、メモリバッファがあり、アプリケーションはそのバッファに読み書きできます。したがって、端末ディスプレイを特定のメモリ領域 (つまり 0x10000) に接続できるかどうか疑問に思っていました。RT アプリがメッセージを 0x10000 に「印刷」すると、Linux 端末はメッセージを表示しますか?

4

3 に答える 3

1

LinuxでIPCを実行する方法はいくつかあり、通常はファイル記述子が関係します。私の意見では、あなたの最善の策はあなたがしていることを続けることです、あなたが言ったようにそれはおそらくやり過ぎです、しかしあなた自身の共有メモリソリューションを実装しようとすることは間違いなくもっとやり過ぎです。

編集:

コメントで述べたように、リアルタイムプロセスを実行しているという事実は物事を先送りにし、ネイティブIPCはおそらく最善の策ではありません。これが私がグーグルで検索したばかりの記事で、あなたが探している答えを提供しているようです。

すべてを読みたくない場合は、必要な通信の種類に応じて、使用する同時実行プリミティブとしてFIFOまたは共有メモリのいずれかを提案します。個人的な経験から、FIFOは、同期についての心配がはるかに少ないため、長期的には頭痛の種が少なくなります。

端末でプログラムを監視する場合は、fifo /共有メモリから読み取り、stdoutにメッセージを送信する小さなプログラムを作成する必要があります。

于 2010-12-29T04:41:31.867 に答える
1

「メールボックス」技術を使用して、一種の仮想シリアル ポートを構築できます。単純な作業用接続の半分について説明します。おそらく、コマンドを送信して応答を取得できるように、これらのいずれかを各方向に接続する必要があります。

カーネルの初期化中にメモリのチャンクを予約します。多くの場合 1 ページであるため、4k としましょう。ただし、256 バイトまたは 16 バイトでも機能します。もう一方の方向のために 1 秒予約します。

チャネルの「ライター」が何かを言いたい場合、まず最初の 32 ビット ワードがゼロかどうかをチェックします。そうであれば、5 番目のバイトから始めて、最大 4k - 4 = 4092 バイトまでのメッセージ (テキスト データまたはバイナリ データなど) を書き込みます。次に、最初のワードを、書き込んだバイト数に等しく設定します。

受信側は、受信しているチャネルの最初のワードのバイト カウントを監視します。ゼロ以外のバイト カウントを確認すると、メモリからそのバイト数を読み取ります。次に、バイト カウントを 0 に設定して、新しいメッセージを都合のよいときに書き込むことができることをライターに示します。

これが依存する唯一のことは、実際に実メモリにアクセスするか、同じキャッシュを介して作業することと、バイトカウントを書き込むためのアトミック書き込み操作があることです (32 ビットのアトミック書き込みがない場合は、16 を使用します)。とにかく十分なビット数、またはバッファを小さくして8ビット数を使用します)。ライターはゼロの場合にのみゼロ以外の値に設定でき、リーダーはゼロ以外の場合にのみゼロの値に設定できるため、すべてうまくいきます。

もちろん、これは単純なメカニズムであり、いずれかの側が他方によってブロックされる可能性があります。ただし、メッセージのソースとなるコンポーネントを設計して、それを考慮に入れることができます。また、複数のメッセージを処理する方法を考え出すか、優先度またはエラー報告チャネルを並行して追加することで、拡張することもできます。

ああ、これをコーディングする前に、Web 検索を行ってください。RTとLinuxコンポーネントを接続するために、このようなメカニズムまたは他の何かが利用できるメカニズムがすでにあると確信しています。しかし、自分でそれを行うことを学ぶことも興味深い場合があります。これは、機能を提供する OS のない小規模な組み込みシステムでこの種の問題に遭遇した場合に必要です。

于 2010-12-29T04:30:11.670 に答える
0

共有メモリ fifo システムを使用してプロセス間で通信することに成功しました (ただし、同じシナリオではありません)。重要なのは、1 つのスレッドのみがプロデューサーになり、1 つのスレッドがコンシューマーになることができるということです。また、Chris Stratton が述べたように、キャッシュは適切なメモリ バリアを使用して適切に処理されることを確認する必要があります。Linux には、メモリ バリア用の非常に単純な API があります。リアルタイム アプリで何が利用できるかはわかりません。メモリバリアが必要な場所を特定しようとしました。

以下は、テストされていない (そして完全に最適化されていない) 共有 fifo の実装です。RT アプリは fifo に文字を書き込むことができ、Linux アプリまたはドライバーは fifo から文字を読み取ることができます。理想的には、データの準備が整ったことを Linux 側に通知するメカニズムを用意する必要があります (おそらく、RT 側が突いたときに割り込みを発生させる未使用の GPIO でしょうか?)。それ以外の場合、Linux 側は fifo 内のデータをポーリングできますが、通常の理由から、これはおそらく理想的ではありません。

struct fifo {
    char volatile* buf;
    int buf_len;
    int volatile head;  // index to first char in the fifo
    int volatile tail;  // index to next empty slot in fifo
                         // if (head == tail) then fifo is empty
                         // if (tail < head) the fifo has 'wrapped'
};

void fifo_init( struct fifo* pFifo, char* buf, int buf_len)
{
    pFifo->buf = buf;
    pFifo->buf_len = buf_len;
    pFifo->head = 0;
    pFifo->tail = 0;
}

int fifo_is_full( struct fifo* pFifo)
{
    int head;
    int tail;

    // a read barrier may be required here
    head = pFifo->head;
    tail = pFifo->tail;

    // fifo is full if ading another char would cause
    //    tail == head
    ++tail;
    if (tail == pFifo->buf_len) {
        tail = 0;
    }

    return (tail == head);
}


int  fifo_is_empty(  struct fifo* pFifo)
{
    int head;
    int tail;

    // a read barrier may be required here
    head = pFifo->head;
    tail = pFifo->tail;

    return head == tail;
}


// this function is the only one that modifies
// the pFifo->tail index.  It can only be used
// by a single writer thread.
int fifo_putchar( struct fifo* pFifo, char c)
{
    int tail = pFifo->tail;

    if (fifo_is_full(pFifo)) return 0;

    pFifo->buf[tail] = c;
    ++tail;
    if (tail == pFifo->buf_len) {
        tail = 0;
    }

    //note: the newly placed character isn't actually 'in' the fifo
    //  as far as the reader thread is concerned until the following
    //  statement is run    
    pFifo->tail = tail;

    // a write barrier may need to be placed here depending on 
    // the system.  Microsoft compilers place a barrier by virtue of
    // the volatile keyword, on a Linux system a `wmb()` may be needed
    // other systems will have other requirements
    return 1;
}


// this function is the only one that modified the
// pFifo->head index.  It can only be used by a single
// reader thread.
int fifo_getchar( struct fifo* pFifo, char* pC)
{
    char c;
    int head = pFifo->head;

    if (fifo_is_empty(pFifo)) return 0;

    // a read barrier may be required here depending on the system
    c = pFifo->buf[head];

    ++head;
    if (head == pFifo->buf_len) {
        head = 0;
    }

    // as far as the write thread is concerned, the char 
    // hasn't been removed until this statement is executed
    pFifo->head = head;

    // a write barrier might be required

    *pC = c;
    return 1;
}

インデックスを更新するときは、プラットフォームの「アトミック」API を使用する方が適切な場合があります。

実行できるいくつかの最適化:

  • fifo サイズが 2 の累乗に制限されている場合、インデックスを適切にマスキングすることでラッピングを処理できます。
  • put/get 関数を変更するか、追加の get/put 関数を追加して文字列またはデータ バイトの配列を受け入れることができ、文字列/配列を FIFO バッファに (またはから) より効率的にコピーできます。

このセットアップの鍵はhead、データが読み取られるまでインデックスが更新されない限り、ライターがデータを上書きすることを心配することなく、リーダーが fifo 内のデータを読み取ることができることです。tailライターの場合も同様です。データがバッファーに書き込まれるまでインデックスが更新されない限り、バッファーの「空き」部分に書き込むことができます。唯一の実際の複雑さは、適切なアイテムがマークされvolatile、適切なメモリ バリアが呼び出されることを確認することです。

于 2010-12-30T07:06:27.217 に答える