Saya membaca kode kernel, dan di satu tempat saya melihat ekspresi di dalam if
pernyataan seperti
if (value == (SPINLOCK_SHARED | 1) - 1) {
............
}
di mana SPINLOCK_SHARED = 0x80000000
konstanta 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 ..
c
bit-manipulation
RaGa__M
sumber
sumber
if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1))
.Jawaban:
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
sumber
Kode ditemukan di
_spin_lock_contested
, yang dipanggil dari_spin_lock_quick
ketika orang lain berusaha mendapatkan kunci:Jika tidak ada kontes, maka
count
(nilai sebelumnya) seharusnya0
, tetapi tidak. Inicount
nilai dilewatkan sebagai parameter untuk_spin_lock_contested
sebagaivalue
parameter. Inivalue
kemudian diperiksa denganif
dari OP:Dengan mengingat bahwa itu
value
adalah nilai sebelumnyaspin->counta
, dan yang terakhir telah bertambah 1, kami berharapspin->counta
samavalue + 1
(kecuali ada sesuatu yang berubah pada saat itu).Jadi, memeriksa apakah
spin->counta == SPINLOCK_SHARED | 1
(prasyaratatomic_cmpset_int
) sesuai dengan memeriksa jikavalue + 1 == SPINLOCK_SHARED | 1
, yang dapat ditulis ulang sebagaivalue == (SPINLOCK_SHARED | 1) - 1
(sekali lagi, jika tidak ada yang berubah pada saat itu).Sementara
value == (SPINLOCK_SHARED | 1) - 1
dapat ditulis ulang sebagaimanavalue == 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.
sumber
(SPINLOCK_SHARED | 1) - 1
bagian dapat dimengerti dan jugavalue == SPINLOCK_SHARED
merupakan pemikiran saya, karena kami memeriksa apakah nilai sebelumnya telah ditetapkan bersama-flag. Jika ya, ubah kunci menjadi eksklusif .........if
pemeriksaan ini adalah untuk memeriksa apakahvalue + 1
(yang seharusnya bernilai sama denganspin->counta
jika tidak ada yang berubah pada saat itu) sama denganSPINLOCK_SHARED | 1
. Jika Anda menulisif
cek sebagaivalue == SPINLOCK_SHARED
, maksud ini tidak jelas, dan akan jauh lebih sulit untuk mengetahui apa arti cek tersebut. Menyimpan keduanyaSPINLOCK_SHARED | 1
dan- 1
secara eksplisit diif
cek itu disengaja.if (value + 1 == (SPINLOCK_SHARED | 1) )
?value & SPINLOCK_SHARED
yang lebih mudah dibaca.Saya pikir tujuannya mungkin untuk mengabaikan bit signifikan terendah:
mungkin akan lebih jelas untuk menggunakan ekspresi topeng sedikit?
sumber
Efek dari
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?sumber
Ini adalah cara penulisan topeng agak dikaburkan. Versi Readable:
value == (SPINLOCK_SHARED & ~1u)
.sumber
SPINLOCK_SHARED
konstanta dikenal. Jika mereka hanya mengujiSPINLOCK_SHARED
kehadiran di topeng, mengapa tidakif (value & SPINLOCK_SHARED)
?value == (SPINLOCK_SHARED & ~1u)
tidak setara karenavalue == (SPINLOCK_SHARED | 1) - 1
berfungsi walaupun jenisnyaSPINLOCK_SHARED
lebih lebar dariunsigned
.& ~1u
lebih jelas. Saya berpikir untuk menyarankan& 0xFFFFFFFE
jawaban saya tetapi menyadari bahwa itu juga tidak terlalu jelas. Saran Anda memang memiliki keuntungan singkatnya. :-)0x80000000
. OP telah menyatakan itu didefinisikan dengan#define SPINLOCK_SHARED 0x80000000
, tetapi itu bisa di dalam#if…#endif
dan 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.Kebanyakan seperti ini dilakukan untuk menangani beberapa kasus tambahan. Misalnya, dalam hal ini, kita mengatakan bahwa
SPINLOCK_SHARED
tidak boleh 1:sumber
SPINLOCK_SHARED
adalah konstanta yang didefinisikan dan variabel yang diujivalue
. Dalam hal ini misteri itu tetap ada.| 1) - 1
bagian itu, ketika SPINLOCK_SHARED memegang0x80000000
apa yang akan menjadi dampaknya| 1) - 1
?SPINLOCK_SHARED
tidak 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.