@@ -523,11 +523,11 @@ CPU 에게 기대할 수 있는 최소한의 보장사항 몇가지가 있습니
523523 즉, ACQUIRE 는 최소한의 "취득" 동작처럼, 그리고 RELEASE 는 최소한의 "공개"
524524 처럼 동작한다는 의미입니다.
525525
526- core-api/atomic_ops.rst 에서 설명되는 어토믹 오퍼레이션들 중에는 완전히
527- 순서잡힌 것들과 (배리어를 사용하지 않는) 완화된 순서의 것들 외에 ACQUIRE 와
528- RELEASE 부류의 것들도 존재합니다. 로드와 스토어를 모두 수행하는 조합된 어토믹
529- 오퍼레이션에서, ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE 는
530- 해당 오퍼레이션의 스토어 부분에만 적용됩니다.
526+ atomic_t.txt 에 설명된 어토믹 오퍼레이션들 중 일부는 완전히 순서잡힌 것들과
527+ (배리어를 사용하지 않는) 완화된 순서의 것들 외에 ACQUIRE 와 RELEASE 부류의
528+ 것들도 존재합니다. 로드와 스토어를 모두 수행하는 조합된 어토믹 오퍼레이션에서,
529+ ACQUIRE 는 해당 오퍼레이션의 로드 부분에만 적용되고 RELEASE 는 해당
530+ 오퍼레이션의 스토어 부분에만 적용됩니다.
531531
532532메모리 배리어들은 두 CPU 간, 또는 CPU 와 디바이스 간에 상호작용의 가능성이 있을
533533때에만 필요합니다. 만약 어떤 코드에 그런 상호작용이 없을 것이 보장된다면, 해당
@@ -617,7 +617,22 @@ RELEASE 부류의 것들도 존재합니다. 로드와 스토어를 모두 수
617617이 변경은 앞의 처음 두가지 결과 중 하나만이 발생할 수 있고, 세번째의 결과는
618618발생할 수 없도록 합니다.
619619
620- 데이터 의존성 배리어는 의존적 쓰기에 대해서도 순서를 잡아줍니다:
620+
621+ [!] 이 상당히 반직관적인 상황은 분리된 캐시를 가지는 기계들에서 가장 잘
622+ 발생하는데, 예를 들면 한 캐시 뱅크는 짝수 번호의 캐시 라인들을 처리하고, 다른
623+ 뱅크는 홀수 번호의 캐시 라인들을 처리하는 경우임을 알아두시기 바랍니다. 포인터
624+ P 는 짝수 번호 캐시 라인에 저장되어 있고, 변수 B 는 홀수 번호 캐시 라인에
625+ 저장되어 있을 수 있습니다. 여기서 값을 읽어오는 CPU 의 캐시의 홀수 번호 처리
626+ 뱅크는 열심히 일감을 처리중인 반면 홀수 번호 처리 뱅크는 할 일 없이 한가한
627+ 중이라면 포인터 P (&B) 의 새로운 값과 변수 B 의 기존 값 (2) 를 볼 수 있습니다.
628+
629+
630+ 의존적 쓰기들의 순서를 맞추는데에는 데이터 의존성 배리어가 필요치 않은데, 이는
631+ 리눅스 커널이 지원하는 CPU 들은 (1) 쓰기가 정말로 일어날지, (2) 쓰기가 어디에
632+ 이루어질지, 그리고 (3) 쓰여질 값을 확실히 알기 전까지는 쓰기를 수행하지 않기
633+ 때문입니다. 하지만 "컨트롤 의존성" 섹션과
634+ Documentation/RCU/rcu_dereference.txt 파일을 주의 깊게 읽어 주시기 바랍니다:
635+ 컴파일러는 매우 창의적인 많은 방법으로 종속성을 깰 수 있습니다.
621636
622637 CPU 1 CPU 2
623638 =============== ===============
@@ -626,28 +641,19 @@ RELEASE 부류의 것들도 존재합니다. 로드와 스토어를 모두 수
626641 <쓰기 배리어>
627642 WRITE_ONCE(P, &B);
628643 Q = READ_ONCE(P);
629- <데이터 의존성 배리어>
630- *Q = 5;
644+ WRITE_ONCE(*Q, 5);
631645
632- 이 데이터 의존성 배리어는 Q 로의 읽기가 *Q 로의 스토어와 순서를 맞추게
633- 해줍니다. 이는 다음과 같은 결과를 막습니다:
646+ 따라서, Q 로의 읽기와 *Q 로의 쓰기 사이에는 데이터 종속성 배리어가 필요치
647+ 않습니다. 달리 말하면, 데이터 종속성 배리어가 없더라도 다음 결과는 생기지
648+ 않습니다:
634649
635650 (Q == &B) && (B == 4)
636651
637652이런 패턴은 드물게 사용되어야 함을 알아 두시기 바랍니다. 무엇보다도, 의존성
638653순서 규칙의 의도는 쓰기 작업을 -예방- 해서 그로 인해 발생하는 비싼 캐시 미스도
639654없애려는 것입니다. 이 패턴은 드물게 발생하는 에러 조건 같은것들을 기록하는데
640- 사용될 수 있고, 이렇게 배리어를 사용해 순서를 지키게 함으로써 그런 기록이
641- 사라지는 것을 막습니다.
642-
643-
644- [!] 상당히 비직관적인 이 상황은 분리된 캐시를 가진 기계, 예를 들어 한 캐시
645- 뱅크가 짝수번 캐시 라인을 처리하고 다른 뱅크는 홀수번 캐시 라인을 처리하는 기계
646- 등에서 가장 잘 발생합니다. 포인터 P 는 홀수 번호의 캐시 라인에 있고, 변수 B 는
647- 짝수 번호 캐시 라인에 있다고 생각해 봅시다. 그런 상태에서 읽기 작업을 하는 CPU
648- 의 짝수번 뱅크는 할 일이 쌓여 매우 바쁘지만 홀수번 뱅크는 할 일이 없어 아무
649- 일도 하지 않고 있었다면, 포인터 P 는 새 값 (&B) 을, 그리고 변수 B 는 옛날 값
650- (2) 을 가지고 있는 상태가 보여질 수도 있습니다.
655+ 사용될 수 있으며, CPU의 자연적인 순서 보장이 그런 기록들을 사라지지 않게
656+ 해줍니다.
651657
652658
653659데이터 의존성 배리어는 매우 중요한데, 예를 들어 RCU 시스템에서 그렇습니다.
@@ -1848,8 +1854,7 @@ Mandatory 배리어들은 SMP 시스템에서도 UP 시스템에서도 SMP 효
18481854 이 코드는 객체의 업데이트된 death 마크가 레퍼런스 카운터 감소 동작
18491855 *전에* 보일 것을 보장합니다.
18501856
1851- 더 많은 정보를 위해선 Documentation/core-api/atomic_ops.rst 문서를 참고하세요.
1852- 어디서 이것들을 사용해야 할지 궁금하다면 "어토믹 오퍼레이션" 서브섹션을
1857+ 더 많은 정보를 위해선 Documentation/atomic_{t,bitops}.txt 문서를
18531858 참고하세요.
18541859
18551860
@@ -2468,86 +2473,7 @@ _않습니다_.
24682473전체 메모리 배리어를 내포하고 또 일부는 내포하지 않지만, 커널에서 상당히
24692474의존적으로 사용하는 기능 중 하나입니다.
24702475
2471- 메모리의 어떤 상태를 수정하고 해당 상태에 대한 (예전의 또는 최신의) 정보를
2472- 리턴하는 어토믹 오퍼레이션은 모두 SMP-조건적 범용 메모리 배리어(smp_mb())를
2473- 실제 오퍼레이션의 앞과 뒤에 내포합니다. 이런 오퍼레이션은 다음의 것들을
2474- 포함합니다:
2475-
2476- xchg();
2477- atomic_xchg(); atomic_long_xchg();
2478- atomic_inc_return(); atomic_long_inc_return();
2479- atomic_dec_return(); atomic_long_dec_return();
2480- atomic_add_return(); atomic_long_add_return();
2481- atomic_sub_return(); atomic_long_sub_return();
2482- atomic_inc_and_test(); atomic_long_inc_and_test();
2483- atomic_dec_and_test(); atomic_long_dec_and_test();
2484- atomic_sub_and_test(); atomic_long_sub_and_test();
2485- atomic_add_negative(); atomic_long_add_negative();
2486- test_and_set_bit();
2487- test_and_clear_bit();
2488- test_and_change_bit();
2489-
2490- /* exchange 조건이 성공할 때 */
2491- cmpxchg();
2492- atomic_cmpxchg(); atomic_long_cmpxchg();
2493- atomic_add_unless(); atomic_long_add_unless();
2494-
2495- 이것들은 메모리 배리어 효과가 필요한 ACQUIRE 부류와 RELEASE 부류 오퍼레이션들을
2496- 구현할 때, 그리고 객체 해제를 위해 레퍼런스 카운터를 조정할 때, 암묵적 메모리
2497- 배리어 효과가 필요한 곳 등에 사용됩니다.
2498-
2499-
2500- 다음의 오퍼레이션들은 메모리 배리어를 내포하지 _않기_ 때문에 문제가 될 수
2501- 있지만, RELEASE 부류의 오퍼레이션들과 같은 것들을 구현할 때 사용될 수도
2502- 있습니다:
2503-
2504- atomic_set();
2505- set_bit();
2506- clear_bit();
2507- change_bit();
2508-
2509- 이것들을 사용할 때에는 필요하다면 적절한 (예를 들면 smp_mb__before_atomic()
2510- 같은) 메모리 배리어가 명시적으로 함께 사용되어야 합니다.
2511-
2512-
2513- 아래의 것들도 메모리 배리어를 내포하지 _않기_ 때문에, 일부 환경에서는 (예를
2514- 들면 smp_mb__before_atomic() 과 같은) 명시적인 메모리 배리어 사용이 필요합니다.
2515-
2516- atomic_add();
2517- atomic_sub();
2518- atomic_inc();
2519- atomic_dec();
2520-
2521- 이것들이 통계 생성을 위해 사용된다면, 그리고 통계 데이터 사이에 관계가 존재하지
2522- 않는다면 메모리 배리어는 필요치 않을 겁니다.
2523-
2524- 객체의 수명을 관리하기 위해 레퍼런스 카운팅 목적으로 사용된다면, 레퍼런스
2525- 카운터는 락으로 보호되는 섹션에서만 조정되거나 호출하는 쪽이 이미 충분한
2526- 레퍼런스를 잡고 있을 것이기 때문에 메모리 배리어는 아마 필요 없을 겁니다.
2527-
2528- 만약 어떤 락을 구성하기 위해 사용된다면, 락 관련 동작은 일반적으로 작업을 특정
2529- 순서대로 진행해야 하므로 메모리 배리어가 필요할 수 있습니다.
2530-
2531- 기본적으로, 각 사용처에서는 메모리 배리어가 필요한지 아닌지 충분히 고려해야
2532- 합니다.
2533-
2534- 아래의 오퍼레이션들은 특별한 락 관련 동작들입니다:
2535-
2536- test_and_set_bit_lock();
2537- clear_bit_unlock();
2538- __clear_bit_unlock();
2539-
2540- 이것들은 ACQUIRE 류와 RELEASE 류의 오퍼레이션들을 구현합니다. 락 관련 도구를
2541- 구현할 때에는 이것들을 좀 더 선호하는 편이 나은데, 이것들의 구현은 많은
2542- 아키텍쳐에서 최적화 될 수 있기 때문입니다.
2543-
2544- [!] 이런 상황에 사용할 수 있는 특수한 메모리 배리어 도구들이 있습니다만, 일부
2545- CPU 에서는 사용되는 어토믹 인스트럭션 자체에 메모리 배리어가 내포되어 있어서
2546- 어토믹 오퍼레이션과 메모리 배리어를 함께 사용하는 게 불필요한 일이 될 수
2547- 있는데, 그런 경우에 이 특수 메모리 배리어 도구들은 no-op 이 되어 실질적으로
2548- 아무일도 하지 않습니다.
2549-
2550- 더 많은 내용을 위해선 Documentation/core-api/atomic_ops.rst 를 참고하세요.
2476+ 더 많은 내용을 위해선 Documentation/atomic_t.txt 를 참고하세요.
25512477
25522478
25532479디바이스 액세스
0 commit comments