(x | y) - y tại sao nó không thể đơn giản là x hoặc thậm chí `x | 0`


47

Tôi đang đọc mã hạt nhân và ở một nơi tôi đã thấy một biểu thức bên trong ifcâu lệnh như

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

trong đó SPINLOCK_SHARED = 0x80000000một hằng số được xác định trước.

Tôi tự hỏi tại sao chúng ta cần (SPINLOCK_SHARED | 1) - 1- cho mục đích chuyển đổi loại? kết quả của biểu thức sẽ là 80000000-- giống như 0x80000000, phải không? chưa, tại sao ORing 1 và trừ 1 vấn đề?

Có cảm giác như tôi đang thiếu để có được thứ gì đó ..


3
#define SPINLOCK_SHARED 0x80000000
RaGa__M

1
Tôi nghi ngờ không có lý do. Có thể là một điều sao chép-dán. Bạn có thể thêm chính xác nơi bạn tìm thấy cái này không (phiên bản của kernel nào, tập tin nào, v.v.).
Sander De Dycker


2
Các tập tin mã nguồn tương tự cũng chứa if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1)).
Eric Postpischil

2
Sau đó, tôi nghĩ rằng chúng ta cần phải hỏi tác giả tại sao nó đã được thay đổi.
funnydman

Câu trả lời:


1

Nó chỉ được thực hiện theo cách đó cho rõ ràng, đó là tất cả. Đó là bởi vì nguyên tử_fetchadd_int () (ví dụ: sys / spinlock2.h) trả về giá trị PRIOR cho phép cộng / trừ và giá trị đó được truyền cho _spin_lock_contested ()

Lưu ý rằng trình biên dịch C hoàn toàn tính toán trước tất cả các biểu thức hằng. Trong thực tế, trình biên dịch thậm chí có thể tối ưu hóa mã nội tuyến dựa trên các điều kiện sử dụng các đối số thủ tục được truyền vào khi các thủ tục được truyền hằng trong các đối số đó. Đây là lý do tại sao lockmgr () nội tuyến trong sys / lock.h có một câu lệnh tình huống .... bởi vì toàn bộ câu lệnh trường hợp đó sẽ được tối ưu hóa và chuyển thành một cuộc gọi trực tiếp đến hàm thích hợp.

Ngoài ra, trong tất cả các chức năng khóa này, phần trên của các op nguyên tử lùn tất cả các phép tính khác theo hai hoặc ba bậc độ lớn.

-Matt


Câu trả lời này là của Tác giả !!!
RaGa__M

31

Mã được tìm thấy _spin_lock_contested, được gọi từ _spin_lock_quickkhi người khác đang cố lấy khóa:

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

Nếu không có cuộc thi, thì count(giá trị trước đó) sẽ là 0, nhưng không phải vậy. Đây countgiá trị được thông qua như là tham số để _spin_lock_contestedvaluetham số. Điều này valuesau đó được kiểm tra với iftừ 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;
}

Hãy nhớ rằng đó valuelà giá trị trước đó và giá trị spin->countasau đã được tăng thêm 1, chúng tôi hy vọng spin->countasẽ bằng nhau value + 1(trừ khi có gì đó đã thay đổi trong thời gian này).

Vì vậy, kiểm tra xem spin->counta == SPINLOCK_SHARED | 1(điều kiện tiên quyết của atomic_cmpset_int) tương ứng với việc kiểm tra xem value + 1 == SPINLOCK_SHARED | 1, có thể được viết lại thành value == (SPINLOCK_SHARED | 1) - 1(một lần nữa, nếu không có gì thay đổi trong thời gian đó).

Mặc dù value == (SPINLOCK_SHARED | 1) - 1có thể được viết lại value == SPINLOCK_SHARED, nhưng nó vẫn để làm rõ ý định so sánh (nghĩa là so sánh giá trị gia tăng trước đó với giá trị thử nghiệm).

Hoặc iow. câu trả lời dường như là: cho sự rõ ràng và thống nhất mã.


Cảm ơn phản hồi của bạn, mọi thứ trừ (SPINLOCK_SHARED | 1) - 1một phần đều có thể hiểu được và value == SPINLOCK_SHAREDtôi cũng nghĩ vậy, bởi vì chúng tôi đang kiểm tra xem giá trị trước đó có chia sẻ cờ hay không. Nếu có, hãy biến khóa thành độc quyền .........
RaGa__M

1
@RaGa__M: mục đích của việc ifkiểm tra là kiểm tra xem value + 1(có nên có cùng giá trị như spin->countakhi không có gì thay đổi trong thời gian đó) bằng không SPINLOCK_SHARED | 1. Nếu bạn viết ifséc là value == SPINLOCK_SHARED, mục đích này không rõ ràng và sẽ khó khăn hơn rất nhiều để tìm ra ý nghĩa của séc. Giữ cả hai SPINLOCK_SHARED | 1- 1rõ ràng trong ifkiểm tra là cố ý.
Sander De Dycker

Nhưng nó thực sự gây ra nhầm lẫn.
RaGa__M

Tại sao không if (value + 1 == (SPINLOCK_SHARED | 1) )?
Pablo H

Chà .... đơn giản là nó có thể value & SPINLOCK_SHAREDdễ đọc hơn.
RaGa__M

10

Tôi nghĩ rằng mục tiêu có lẽ là bỏ qua bit đáng kể thấp nhất:

  • Nếu SPINLOCK_SHARED thể hiện ở dạng nhị phân là xxx0 -> kết quả là xxx0
  • Nếu SPINLOCK_SHARED = xxx1 -> kết quả cũng là xxx0

có lẽ đã rõ ràng hơn để sử dụng một biểu thức mặt nạ bit?


8
Đó là những gì mã làm, nhưng câu hỏi là tại sao bạn sẽ làm điều đó cho một hằng số xác định không có tập bit ít quan trọng nhất?
Sander De Dycker

4
@SanderDeDycker Vì nhân Linux?
Lundin

9
@Lundin Hạt nhân linux không được miễn thực hành mã hóa dễ hiểu. Hoàn toàn ngược lại.
Qix - MONICA ĐƯỢC PHÂN BIỆT

2
@Qix Nếu bạn nói vậy. Tôi là một fan hâm mộ lớn của Linux cho đến khi tôi xem mã và đọc tài liệu kiểu mã hóa kernel. Ngày nay tôi giữ khoảng cách an toàn 10 mét với máy tính Linux.
Lundin

2
@Qix Nah Tôi đánh giá nó dựa trên mã nguồn của nó ...
Lundin

4

Ảnh hưởng của

(SPINLOCK_SHARED | 1) - 1

là để đảm bảo rằng bit thứ tự thấp của kết quả được xóa trước khi so sánh với value. Tôi đồng ý rằng nó có vẻ khá vô nghĩa nhưng rõ ràng bit thứ tự thấp có cách sử dụng hoặc ý nghĩa cụ thể không rõ ràng trong mã này và tôi nghĩ rằng chúng ta phải cho rằng các nhà phát triển có lý do chính đáng để làm điều này. Một câu hỏi thú vị sẽ là - có phải mẫu này ( | 1) -1) được sử dụng trong toàn bộ cơ sở mã mà bạn đang xem không?


2

Đó là một cách khó hiểu để viết một mặt nạ bit. Phiên bản dễ đọc : value == (SPINLOCK_SHARED & ~1u).


5
Vâng, nhưng tại sao . OP đang hỏi tại sao điều này sẽ xảy ra nếu SPINLOCK_SHAREDlà hằng số đã biết. Nếu họ chỉ đơn giản là thử nghiệm để SPINLOCK_SHAREDcó mặt trong mặt nạ, tại sao không if (value & SPINLOCK_SHARED)?
Qix - MONICA ĐƯỢC PHÂN BIỆT

4
value == (SPINLOCK_SHARED & ~1u)không tương đương vì value == (SPINLOCK_SHARED | 1) - 1hoạt động ngay cả khi loại SPINLOCK_SHAREDrộng hơn unsigned.
Eric Postpischil

4
Thành thật mà nói, tôi không chắc điều đó & ~1urõ ràng hơn. Tôi đã nghĩ đến việc gợi ý & 0xFFFFFFFEtrong câu trả lời của mình nhưng nhận ra điều đó cũng không thực sự rõ ràng. Đề nghị của bạn không có lợi thế của sự ngắn gọn, mặc dù. :-)
Bob Jarvis - Phục hồi Monica

6
@Lundin: Chúng tôi không biết rằng nó sẽ được 0x80000000. OP đã tuyên bố nó được định nghĩa với #define SPINLOCK_SHARED 0x80000000, nhưng có thể ở bên trong #if…#endifvà một định nghĩa khác được sử dụng trong các trường hợp khác hoặc tác giả của mã này có thể đã dự định nó hoạt động ngay cả khi định nghĩa được chỉnh sửa hoặc mã được biên dịch với các tiêu đề khác định nghĩa nó khác nhau Bất kể, hai đoạn mã không tương đương với nhau.
Eric Postpischil

2
@ BobJarvis-ReinstateMonica Điều đó rõ ràng hơn nhiều đối với những người làm việc với các nhà khai thác bitwise mỗi ngày. Trộn bitwise với số học thông thường là khó hiểu.
Lundin

0

Hầu hết như thế này được thực hiện để xử lý một số trường hợp bổ sung. Ví dụ: trong trường hợp này, chúng tôi nói rằng SPINLOCK_SHAREDkhông thể là 1:

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0

2
Nó sẽ có ý nghĩa nhưng, mặc dù nó không thực sự rõ ràng từ câu hỏi, có vẻ như SPINLOCK_SHAREDlà một hằng số xác định và biến được kiểm tra là value. Trong trường hợp này, sương mù vẫn còn.
Roberto Caboni

Cảm ơn câu trả lời của bạn, nhưng tôi nghĩ trong trường hợp ban đầu SPINLOCK_SHARED không phải là 0x01, bạn đã giữ | 1) - 1phần tho, khi SPINLOCK_SHARED giữ 0x80000000tác động của điều | 1) - 1gì?
RaGa__M

Lý do duy nhất tôi có thể nghĩ đến là họ muốn bảo vệ chống lại SPINLOCK_SHAREDsự thay đổi trong tương lai. Nhưng nó không rõ ràng. Tôi sẽ viết thư cho các nhà phát triển hạt nhân và yêu cầu bình luận làm rõ hoặc để biểu thức được sắp xếp lại để nó tự ghi lại.
Qix - MONICA ĐƯỢC PHÂN BIỆT
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.