(x | y) - y mengapa tidak bisa hanya x atau bahkan `x | 0`

47

Saya membaca kode kernel, dan di satu tempat saya melihat ekspresi di dalam ifpernyataan seperti

if (value == (SPINLOCK_SHARED | 1) - 1) {
         ............
}

di mana SPINLOCK_SHARED = 0x80000000konstanta yang ditentukan sebelumnya.

Saya heran mengapa kita perlu (SPINLOCK_SHARED | 1) - 1- untuk tujuan konversi tipe? hasil dari ekspresi akan menjadi 80000000 - sama dengan 0x80000000, bukan? namun, mengapa ORing 1 dan Mengurangkan 1 penting?

Memiliki perasaan seperti saya kehilangan untuk mendapatkan sesuatu ..

RaGa__M
sumber
3
#define SPINLOCK_SHARED 0x80000000
RaGa__M
1
Saya curiga tidak ada alasan. Mungkin hal copy-paste. Bisakah Anda menambahkan di mana tepatnya Anda menemukan ini (versi kernel mana, file mana, dll.).
Sander De Dycker
2
File kode sumber yang sama juga mengandung if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1)).
Eric Postpischil
2
Maka saya pikir kita perlu bertanya kepada penulis mengapa itu diubah.
funnydman

Jawaban:

1

Itu hanya dilakukan dengan cara itu untuk kejelasan, itu saja. Itu karena atomic_fetchadd_int () (dalam contoh sys / spinlock2.h) mengembalikan nilai PRIOR ke penjumlahan / pengurangan, dan nilai tersebut diteruskan ke _spin_lock_contested ()

Perhatikan bahwa kompiler C sepenuhnya menghitung semua ekspresi konstan. Bahkan, kompiler bahkan dapat mengoptimalkan kode inline berdasarkan kondisional yang menggunakan argumen prosedur masuk ketika prosedur dilewatkan konstanta dalam argumen tersebut. Inilah sebabnya mengapa lockmgr () sebaris di sys / lock.h memiliki pernyataan kasus .... karena seluruh pernyataan kasus akan dioptimalkan dan dipindahkan ke panggilan langsung ke fungsi yang sesuai.

Juga, dalam semua fungsi penguncian ini, overhead ops atom mengerdilkan semua perhitungan lainnya dengan dua atau tiga orde besarnya.

-Matt

Matthew Dillon
sumber
Jawaban ini dari Penulis !!!
RaGa__M
31

Kode ditemukan di _spin_lock_contested, yang dipanggil dari _spin_lock_quickketika orang lain berusaha mendapatkan kunci:

count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
    _spin_lock_contested(spin, ident, count);
}

Jika tidak ada kontes, maka count(nilai sebelumnya) seharusnya 0, tetapi tidak. Ini countnilai dilewatkan sebagai parameter untuk _spin_lock_contestedsebagai valueparameter. Ini valuekemudian diperiksa dengan ifdari OP:

/*
 * WARNING! Caller has already incremented the lock.  We must
 *      increment the count value (from the inline's fetch-add)
 *      to match.
 *
 * Handle the degenerate case where the spinlock is flagged SHARED
 * with only our reference.  We can convert it to EXCLUSIVE.
 */
if (value == (SPINLOCK_SHARED | 1) - 1) {
    if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
        return;
}

Dengan mengingat bahwa itu valueadalah nilai sebelumnya spin->counta, dan yang terakhir telah bertambah 1, kami berharap spin->countasama value + 1(kecuali ada sesuatu yang berubah pada saat itu).

Jadi, memeriksa apakah spin->counta == SPINLOCK_SHARED | 1(prasyarat atomic_cmpset_int) sesuai dengan memeriksa jika value + 1 == SPINLOCK_SHARED | 1, yang dapat ditulis ulang sebagai value == (SPINLOCK_SHARED | 1) - 1(sekali lagi, jika tidak ada yang berubah pada saat itu).

Sementara value == (SPINLOCK_SHARED | 1) - 1dapat ditulis ulang sebagaimana value == SPINLOCK_SHARED, dibiarkan apa adanya, untuk memperjelas maksud perbandingan (mis. Untuk membandingkan nilai sebelumnya yang ditambahkan dengan nilai tes).

Atau iow. jawabannya adalah: untuk kejelasan dan konsistensi kode.

Sander De Dycker
sumber
Terima kasih atas tanggapan Anda, semuanya kecuali (SPINLOCK_SHARED | 1) - 1bagian dapat dimengerti dan juga value == SPINLOCK_SHAREDmerupakan pemikiran saya, karena kami memeriksa apakah nilai sebelumnya telah ditetapkan bersama-flag. Jika ya, ubah kunci menjadi eksklusif .........
RaGa__M
1
@ RaGa__M: maksud dari ifpemeriksaan ini adalah untuk memeriksa apakah value + 1(yang seharusnya bernilai sama dengan spin->countajika tidak ada yang berubah pada saat itu) sama dengan SPINLOCK_SHARED | 1. Jika Anda menulis ifcek sebagai value == SPINLOCK_SHARED, maksud ini tidak jelas, dan akan jauh lebih sulit untuk mengetahui apa arti cek tersebut. Menyimpan keduanya SPINLOCK_SHARED | 1dan - 1secara eksplisit di ifcek itu disengaja.
Sander De Dycker
Tapi itu justru menyebabkan kebingungan.
RaGa__M
Mengapa tidak if (value + 1 == (SPINLOCK_SHARED | 1) )?
Pablo H
Yah .... itu bisa jadi value & SPINLOCK_SHAREDyang lebih mudah dibaca.
RaGa__M
10

Saya pikir tujuannya mungkin untuk mengabaikan bit signifikan terendah:

  • Jika SPINLOCK_SHARED diekspresikan dalam biner adalah xxx0 -> hasilnya adalah xxx0
  • Jika SPINLOCK_SHARED = xxx1 -> hasilnya juga xxx0

mungkin akan lebih jelas untuk menggunakan ekspresi topeng sedikit?

Guillaume Petitjean
sumber
8
Itulah yang dilakukan kode, tetapi pertanyaannya adalah mengapa Anda melakukan itu untuk konstanta yang didefinisikan yang tidak memiliki bit set paling signifikan?
Sander De Dycker
4
@SanderDeDycker Karena kernel Linux?
Lundin
9
@Lundin Kernel linux tidak dibebaskan dari praktik pengkodean yang dapat dimengerti. Justru sebaliknya.
Qix - MONICA DISALAHKAN
2
@Qix Jika Anda bilang begitu. Saya adalah penggemar berat Linux sampai saya mengintip kode dan membaca dokumen gaya pengkodean kernel. Saat ini saya menjaga jarak keamanan 10 meter ke komputer Linux.
Lundin
2
@ Qix Nah, saya agak menilainya berdasarkan kode sumbernya ...
Lundin
4

Efek dari

(SPINLOCK_SHARED | 1) - 1

adalah untuk memastikan bahwa bit pesanan rendah dari hasil dibersihkan sebelum perbandingan dengan value. Saya setuju bahwa itu tampaknya tidak ada gunanya tetapi tampaknya bit orde rendah memiliki penggunaan atau makna tertentu yang tidak terlihat dalam kode ini, dan saya pikir kita harus berasumsi bahwa para devs memiliki alasan yang baik untuk melakukan ini. Pertanyaan yang menarik adalah - apakah pola yang sama ini ( | 1) -1) digunakan di seluruh basis kode yang Anda lihat?

Bob Jarvis - Pasang kembali Monica
sumber
2

Ini adalah cara penulisan topeng agak dikaburkan. Versi Readable: value == (SPINLOCK_SHARED & ~1u).

Lundin
sumber
5
Ya, tapi mengapa . OP bertanya mengapa ini akan terjadi jika SPINLOCK_SHAREDkonstanta dikenal. Jika mereka hanya menguji SPINLOCK_SHAREDkehadiran di topeng, mengapa tidak if (value & SPINLOCK_SHARED)?
Qix - MONICA DISEBUTKAN
4
value == (SPINLOCK_SHARED & ~1u)tidak setara karena value == (SPINLOCK_SHARED | 1) - 1berfungsi walaupun jenisnya SPINLOCK_SHAREDlebih lebar dari unsigned.
Eric Postpischil
4
Jujur, saya tidak yakin itu & ~1ulebih jelas. Saya berpikir untuk menyarankan & 0xFFFFFFFEjawaban saya tetapi menyadari bahwa itu juga tidak terlalu jelas. Saran Anda memang memiliki keuntungan singkatnya. :-)
Bob Jarvis - Reinstate Monica
6
@Lundin: Kami tidak tahu itu akan terjadi 0x80000000. OP telah menyatakan itu didefinisikan dengan #define SPINLOCK_SHARED 0x80000000, tetapi itu bisa di dalam #if…#endifdan definisi yang berbeda digunakan dalam keadaan lain, atau pembuat kode ini dapat membuatnya berfungsi bahkan jika definisi tersebut diedit atau kode tersebut dikompilasi dengan header lain yang mendefinisikannya secara berbeda. Apapun, dua potong kode itu tidak setara dengan dirinya sendiri.
Eric Postpischil
2
@ BobJarvis-ReinstateMonica Jauh lebih jelas bagi orang yang bekerja dengan operator bitwise setiap hari. Mencampur bitwise dengan aritmatika biasa membingungkan.
Lundin
0

Kebanyakan seperti ini dilakukan untuk menangani beberapa kasus tambahan. Misalnya, dalam hal ini, kita mengatakan bahwa SPINLOCK_SHAREDtidak boleh 1:

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0
Funnydman
sumber
2
Itu masuk akal tetapi, meskipun sebenarnya tidak jelas dari pertanyaan, sepertinya SPINLOCK_SHAREDadalah konstanta yang didefinisikan dan variabel yang diuji value. Dalam hal ini misteri itu tetap ada.
Roberto Caboni
Terima kasih atas balasan Anda, Tapi saya pikir dalam kasus asli SPINLOCK_SHARED bukan 0x01, Anda tetap menggunakan | 1) - 1bagian itu, ketika SPINLOCK_SHARED memegang 0x80000000apa yang akan menjadi dampaknya | 1) - 1?
RaGa__M
Satu-satunya alasan yang dapat saya pikirkan adalah bahwa mereka ingin menjaga agar SPINLOCK_SHAREDtidak berubah di masa depan. Tapi sama sekali tidak jelas. Saya akan menulis ke devs kernel dan meminta komentar klarifikasi untuk dibuat atau untuk ekspresi yang diatur ulang sehingga dokumen itu sendiri.
Qix - MONICA DISALAHKAN