2012-08-10 31 views
12

Tôi đã làm việc trên một hệ điều hành nhúng cho ARM, Tuy nhiên có một vài điều tôi không hiểu về kiến ​​trúc ngay cả sau khi đề cập đến ARMARM và nguồn linux.Hoạt động nguyên tử trong ARM

Hoạt động nguyên tử.

ARM ARM nói rằng lệnh tải và lưu trữ là nguyên tử và thực thi của nó được đảm bảo hoàn thành trước khi trình xử lý ngắt thực thi. Xác nhận bằng cách nhìn vào

arch/arm/include/asm/atomic.h : 
    #define atomic_read(v) (*(volatile int *)&(v)->counter) 
    #define atomic_set(v,i) (((v)->counter) = (i)) 

Tuy nhiên, vấn đề đi kèm trong khi tôi muốn thao tác giá trị này nguyên tử sử dụng các hướng dẫn cpu (atomic_inc, atomic_dec, atomic_cmpxchg vv ..) mà sử dụng LDREX và STREX cho ARMv7 (mục tiêu của tôi) .

ARMARM không nói bất cứ điều gì về ngắt bị chặn trong phần này vì vậy tôi cho rằng có thể xảy ra gián đoạn giữa LDREX và STREX. Điều mà nó đề cập đến là khóa bus nhớ mà tôi đoán chỉ hữu ích cho các hệ thống MP, nơi có thể có nhiều CPU cố gắng truy cập cùng một vị trí cùng một lúc. Nhưng đối với UP (và có thể MP), Nếu một ngắt thời gian (hoặc IPI cho SMP) kích hoạt trong cửa sổ nhỏ này của LDREX và STREX, xử lý ngoại lệ thực thi có thể thay đổi bối cảnh CPU và trở về nhiệm vụ mới, tuy nhiên phần gây sốc đến bây giờ , nó thực hiện 'CLREX' và do đó loại bỏ bất kỳ khóa độc quyền nào được giữ bởi chuỗi trước đó. Vì vậy, làm thế nào tốt hơn là sử dụng LDREX và STREX hơn LDR và ​​STR cho atomicity trên một hệ thống UP?

Tôi đã đọc gì đó về màn hình khóa độc quyền, vì vậy tôi có thể lý thuyết rằng khi chuỗi tiếp tục và thực thi STREX, màn hình os sẽ khiến cuộc gọi này bị lỗi và có thể được phát hiện được thực hiện bằng cách sử dụng giá trị mới trong tiến trình (nhánh trở lại LDREX), tôi có ở đây không?

Trả lời

9

OK, nhận câu trả lời từ số website.

Nếu chuyển đổi ngữ cảnh lên lịch trình sau khi quá trình thực hiện Tải độc quyền nhưng trước khi thực hiện Store-Exclusive, Store-Exclusive trả về kết quả âm sai khi quá trình tiếp tục và bộ nhớ không được cập nhật. Điều này không ảnh hưởng đến chức năng của chương trình, bởi vì quá trình có thể thử lại thao tác ngay lập tức.

8

Ý tưởng đằng sau mô hình/cửa hàng độc quyền tải liên kết là nếu nếu các cửa hàng sau rất sớm sau khi tải, không có hoạt động bộ nhớ can thiệp, và nếu không có gì khác đã chạm vào vị trí, cửa hàng là có khả năng để thành công, nhưng nếu có điều gì đó khác đã chạm vào vị trí, cửa hàng là nhất định để không thành công. Không có gì đảm bảo rằng các cửa hàng sẽ không đôi khi thất bại vì không có lý do rõ ràng; nếu thời gian giữa tải và lưu trữ được giữ ở mức tối thiểu, tuy nhiên, và không có bộ nhớ truy cập giữa chúng, một vòng lặp như:

do 
{ 
    new_value = __LDREXW(dest) + 1; 
} while (__STREXW(new_value, dest)); 

nói chung có thể được dựa vào để thành công trong một vài lần.Nếu tính giá trị mới dựa trên giá trị cũ yêu cầu một số tính toán có ý nghĩa, ta nên viết lại vòng lặp như:

do 
{ 
    old_value = *dest; 

    new_value = complicated_function(old_value); 
} while (CompareAndStore(dest, new_value, old_value) != 0); 

... Assuming CompareAndStore is something like: 

uint32_t CompareAndStore(uint32_t *dest, uint32_t new_value, uint_32 old_value) 
{ 
    do 
    { 
    if (__LDREXW(dest) != old_value) return 1; // Failure 
    } while(__STREXW(new_value, dest); 
    return 0; 
} 

Mã này sẽ phải chạy lại vòng lặp chính của nó nếu có điều gì thay đổi * dest trong khi giá trị mới đang được tính toán , nhưng chỉ vòng lặp nhỏ sẽ cần phải được chạy lại nếu __STREXW thất bại vì một lý do khác [đó là hy vọng không quá khả năng, cho rằng đó sẽ chỉ có khoảng hai hướng dẫn giữa __LDREXW và __STREXW]

Phụ Lục Một ví dụ về một tình huống mà "tính toán giá trị mới dựa trên cũ" có thể phức tạp sẽ là một trong những nơi "giá trị" ar hiệu quả một tham chiếu đến một cấu trúc dữ liệu phức tạp. Mã có thể tìm nạp tham chiếu cũ, lấy được cấu trúc dữ liệu mới từ cũ và sau đó cập nhật tham chiếu. Mô hình này xuất hiện thường xuyên hơn trong các khung được thu gom rác hơn là trong lập trình "kim loại trần", nhưng có nhiều cách nó có thể xuất hiện ngay cả khi lập trình kim loại trần. Các trình phân bổ malloc/calloc bình thường thường không an toàn chủ đề/an toàn ngắt, nhưng các trình phân bổ cho các cấu trúc kích thước cố định thường là. Nếu ta có một "hồ bơi" của một số điện-of-hai số cấu trúc dữ liệu (nói 255), người ta có thể sử dụng một cái gì đó như:

#define FOO_POOL_SIZE_SHIFT 8 
#define FOO_POOL_SIZE (1 << FOO_POOL_SIZE_SHIFT) 
#define FOO_POOL_SIZE_MASK (FOO_POOL_SIZE-1) 

void do_update(void) 
{ 
    // The foo_pool_alloc() method should return a slot number in the lower bits and 
    // some sort of counter value in the upper bits so that once some particular 
    // uint32_t value is returned, that same value will not be returned again unless 
    // there are at least (UINT_MAX)/(FOO_POOL_SIZE) intervening allocations (to avoid 
    // the possibility that while one task is performing its update, a second task 
    // changes the thing to a new one and releases the old one, and a third task gets 
    // given the newly-freed item and changes the thing to that, such that from the 
    // point of view of the first task, the thing never changed.) 

    uint32_t new_thing = foo_pool_alloc(); 
    uint32_t old_thing; 
    do 
    { 
    // Capture old reference 
    old_thing = foo_current_thing; 

    // Compute new thing based on old one 
    update_thing(&foo_pool[new_thing & FOO_POOL_SIZE_MASK], 
     &foo_pool[old_thing & FOO_POOL_SIZE_MASK); 
    } while(CompareAndSwap(&foo_current_thing, new_thing, old_thing) != 0); 
    foo_pool_free(old_thing); 
} 

Nếu có sẽ không thường xuyên có nhiều chủ đề/ngắt/bất cứ cố gắng cập nhật cùng một điều cùng một lúc, phương pháp này nên cho phép cập nhật được thực hiện một cách an toàn. Nếu mối quan hệ ưu tiên sẽ tồn tại trong số những thứ có thể cố gắng cập nhật cùng một mục, ưu tiên cao nhất được đảm bảo thành công trong lần thử đầu tiên, mối quan hệ ưu tiên cao nhất sẽ thành công trên bất kỳ nỗ lực nào không được ưu tiên ưu tiên cao nhất, vv Nếu một người đang sử dụng khóa, tác vụ có mức độ ưu tiên cao nhất muốn thực hiện cập nhật sẽ phải đợi bản cập nhật ưu tiên thấp hơn kết thúc; bằng cách sử dụng mô hình CompareAndSwap, nhiệm vụ có mức ưu tiên cao nhất sẽ không bị ảnh hưởng bởi tác vụ thấp hơn (nhưng sẽ khiến tác vụ thấp hơn phải làm công việc lãng phí).

+0

Tôi đã làm chính xác điều tương tự nhưng phần mà tính toán đáng kể là cần thiết cho giá trị mới, vẫn còn câu đố cho tôi. Sử dụng vòng lặp cmxchg có ý nghĩa bởi vì sau đó màn hình độc quyền sẽ không bị xóa bởi một chuyển ngữ cảnh nhưng việc thực hiện lại máy tính đáng kể đòi hỏi rất nhiều chi phí khi tôi quan sát đường phố thất bại mà không có lý do rõ ràng (UP với IRQ được che dấu trong PSR) như đã đề cập trong bài đăng của bạn. – sgupta

+0

@ user1075375: Xem phụ lục – supercat

+0

Những (__LDREXW & __STREXW) được hỗ trợ nội tại trong trình biên dịch Keil cho bộ xử lý vi điều khiển dòng Cortex-M, thường không có sẵn cho các mục tiêu ARM chính (ví dụ, AArch64) và trình biên dịch (ví dụ: gcc, llvm) đúng? http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABDEEJC.html – ahcox

Các vấn đề liên quan