2017-10-20 11 views
1

ガイドUnderstanding The Linux Kernel, 3rd Editionの章8.2.12。Linuxでのポインタ計算カーネル割り当ての実装

void * kmem_cache_alloc(kmem_cache_t *cachep, int flags) 
{ 
    unsigned long save_flags; 
    void *objp; 
    struct array_cache *ac; 
    local_irq_save(save_flags); 
    ac = cache_p->array[smp_processor_id()]; 
    if (ac->avail) 
    { 
     ac->touched = 1; 
     objp = ((void**)(ac+1))[--ac->avail]; 
    } else 
     objp = cache_alloc_refill(cachep, flags); 
    local_irq_restore(save_flags); return objp; 
} 

ガイドによると、ライン((void**)(ac+1))[--ac->avail]を見て、今すぐ:

をローカルキャッシュアレイは直後に格納されるためスラブオブジェクトを割り当て、以下のコードがあります ((void **)(ac + 1))[ - ac-> avail]は空きオブジェクトのアドレスを取得し、 はac-> availの値を減らします。

しかし、ac(この順で)次のフィールドが含まれていstruct array_cacheを型へのポインタであるので -

[タイプ] unsigned int型

[名前]

役に立ちます[説明]ローカルキャッシュ内の使用可能なオブジェクトへのポインタの数。 フィールドは、キャッシュ内の最初の空きスロットのインデックスとしても機能します。

[タイプ] unsigned int型

[名]は、ローカルキャッシュ内のポインタの最大数であるローカルキャッシュの

[説明]サイズを制限します。

[タイプ]ローカルキャッシュリフィルまたは空にするためunsigned int型

[名前] batch_count

[説明]チャンクサイズ。ローカルキャッシュが、最近使用されている場合

[タイプ] unsigned int型

[名前]は1に

[説明]旗セットに触れました。

のでac+1はまったく意味をなさないavail値(又は逆のエンディアンの場合に3バイト目)の第2バイトを指します。

私はこれを間違った方法で受け取りますか?

答えて

3

はい、間違います。

ポインタの算術演算は、バイトではなく、指し示されている型に関して行われます。

int a[2], *p = a; 

++p; 

これは&a[1]、ないに等しい((char *) &a[0]) + 1pを残し:

が、この考えてみましょう。したがって、インクリメントは実際のポインタ値をsizeof *p、すなわちsizeof (int)だけインクリメントします。

配列インデックスはポインタ演算で機能するので、そのためにもこの方法が必要です。

Cでさまざまなデータ構造を実装して、ある程度のインスタンスで始まり、他のデータ(多くの場合、structのフィールドで記述されています)から始まるメモリブロックを持つことは非常に一般的です。そのデータの最初のバイトはsp + 1にあり、spが表示されたコードと同じようにstructへのポインタであると仮定します。

+0

このタイプのコーディングのより一般的な使用法と例を教えてください。私はこのデータをラップする別の構造体の使用を期待していたでしょう、そして、このラッパー構造体は、他の構造体へのポインタのフィールドと、他のデータを指す別のフィールドを持ちます。この方法はきれいで明確です。なぜこのようなコードを使用するのですか?それは何のために良いですか? – user2162550

関連する問題