日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux Kernel Atomic解析

發(fā)布時(shí)間:2023/12/16 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux Kernel Atomic解析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Atomic

  • 1. Atomic
    • 1.1 SMP read / write
      • 1.1.1 Read
      • 1.1.2 Write
      • 1.1.3 相關(guān)接口
      • 1.1.4 READ_ONCE / WRITE_ONCE
    • 1.2 SMP add / sub
      • 1.2.1 atomic_add
        • 1.2.1.1 atomic_add_return
        • 1.2.1.2 arch_atomic_add_return_relaxed
        • 1.2.1.3 arch_atomic_add_return
        • 小結(jié)
      • 1.2.2 atomic_sub

1. Atomic

1.1 SMP read / write

1.1.1 Read

include/asm-generic/atomic.h#ifndef atomic_read #define atomic_read(v) READ_ONCE((v)->counter) #endif

1.1.2 Write

include/asm-generic/atomic.h#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))

??atomic_readatomic_write函數(shù),通過(guò)READ_ONCEWRITE_ONCE直接讀寫??梢灾苯幼x寫,而不需要考慮原子性的原因是:同一時(shí)刻只允許一個(gè)cpu訪問(wèn)外設(shè)。

??如上圖所示,當(dāng)cpu0與cpu1同時(shí)請(qǐng)求訪問(wèn)ddr時(shí),同一時(shí)刻總線只會(huì)響應(yīng)一個(gè)請(qǐng)求,例如cpu0的request,此時(shí)bus是鎖定狀態(tài);當(dāng)cpu0訪問(wèn)結(jié)束,ddr將鎖放開(kāi)后,cpu1的請(qǐng)求才會(huì)得到ddr響應(yīng)。

1.1.3 相關(guān)接口

atomic_read(v) atomic_set(v, i)

1.1.4 READ_ONCE / WRITE_ONCE

??將讀取的變量使用volatile宏修飾,讓cpu每次都從內(nèi)存中讀取數(shù)據(jù)。

#define READ_ONCE(x) __READ_ONCE(x, 1)#define __READ_ONCE(x, check) \ ({ \union { typeof(x) __val; char __c[1]; } __u; \if (check) \__read_once_size(&(x), __u.__c, sizeof(x)); \else \__read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \__u.__val; \ })static __always_inline void __read_once_size(const volatile void *p, void *res, int size) {__READ_ONCE_SIZE; }#define __READ_ONCE_SIZE \ ({ \switch (size) { \case 1: *(__u8 *)res = *(volatile __u8 *)p; break; \case 2: *(__u16 *)res = *(volatile __u16 *)p; break; \case 4: *(__u32 *)res = *(volatile __u32 *)p; break; \case 8: *(__u64 *)res = *(volatile __u64 *)p; break; \default: \barrier(); \__builtin_memcpy((void *)res, (const void *)p, size); \barrier(); \} \ })

??傳入的第二個(gè)參數(shù)check為1,調(diào)用__read_once_size。
??smp_read_barrier_depends是提供給架構(gòu)實(shí)現(xiàn)內(nèi)存隔離的函數(shù),只有alpha和blackfin定義了,其余架構(gòu)為空函數(shù)。
??返回值為_(kāi)_u.__val,首先__u是一個(gè)union類型,在賦值時(shí)使用的是char __c,在返回時(shí)使用的是typeof(x) __val,它定義了一個(gè)與x變量類型相同的__val變量。
??針對(duì)u8 / u16 / u32 / u64大小的數(shù)據(jù),使用volatile修飾,保證編譯器不優(yōu)化,每次都從內(nèi)存中讀取。對(duì)于其它大小的數(shù)據(jù),在讀的前后調(diào)用barrier,barrier的功能為內(nèi)存屏障,執(zhí)行后,cpu會(huì)從內(nèi)存中讀取數(shù)據(jù)。

??與讀類似,WRITE_ONCE的實(shí)現(xiàn)如下:

#define WRITE_ONCE(x, val) \ ({ \union { typeof(x) __val; char __c[1]; } __u = \{ .__val = (__force typeof(x)) (val) }; \__write_once_size(&(x), __u.__c, sizeof(x)); \__u.__val; \ })static __always_inline void __write_once_size(volatile void *p, void *res, int size) {switch (size) {case 1: *(volatile __u8 *)p = *(__u8 *)res; break;case 2: *(volatile __u16 *)p = *(__u16 *)res; break;case 4: *(volatile __u32 *)p = *(__u32 *)res; break;case 8: *(volatile __u64 *)p = *(__u64 *)res; break;default:barrier();__builtin_memcpy((void *)p, (const void *)res, size);barrier();} }

1.2 SMP add / sub

??再考慮另外一個(gè)問(wèn)題,atomic的加減是否需要特殊保護(hù)?
??如下圖所示,這種情況下就會(huì)發(fā)生讀寫的非原子性操作。

??變量a在cpu0和cpu1分別++后,a應(yīng)該變?yōu)?,但由于同時(shí)對(duì)a的非原子操作,導(dǎo)致重復(fù)的將a++的結(jié)果2寫入內(nèi)存。
??為了保證atomic變量加減的原子性操作,atomic提供的相關(guān)函數(shù)。

1.2.1 atomic_add

??首先,kernel提供了通用性定義,位于include/asm-generic/atomic.h中,實(shí)現(xiàn)如下:

include/asm-generic/atomic.hstatic inline void atomic_add(int i, atomic_t *v) {atomic_add_return(i, v); }

??繼續(xù)查看atomic_add_return的實(shí)現(xiàn)

1.2.1.1 atomic_add_return

??這個(gè)函數(shù)的實(shí)現(xiàn)有兩個(gè)地方,一處為atomic-instrumented.h,一處為atomic-fallback.h。

??在arch_atomic_add_return_relaxed未定義或arch_atomic_add_return已定義時(shí),使用instrumented.h中的定義。

??先來(lái)看一下atomic-instrumented.h中的定義:

include/asm-generic/atomic-instrumented.h#if !defined(arch_atomic_add_return_relaxed) || defined(arch_atomic_add_return) static inline int atomic_add_return(int i, atomic_t *v) {kasan_check_write(v, sizeof(*v));return arch_atomic_add_return(i, v); } #define atomic_add_return atomic_add_return #endif

??在atomic-instrumented.h中條件不滿足,未定義時(shí)。使用atomic-fallback.h中的定義:

include/linux/atomic-fallback.h#ifndef atomic_add_return static inline int atomic_add_return(int i, atomic_t *v) {int ret;__atomic_pre_full_fence();ret = atomic_add_return_relaxed(i, v);__atomic_post_full_fence();return ret; } #define atomic_add_return atomic_add_return #endif

1.2.1.2 arch_atomic_add_return_relaxed

??只有一處定義位置,在arm64中:

arch/arm64/include/asm/atomic.h#define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed

1.2.1.3 arch_atomic_add_return

??該函數(shù)只在arm64和x86中有定義:

1 110 arch/arm64/include/asm/atomic.h <<arch_atomic_add_return>>#define arch_atomic_add_return arch_atomic_add_return2 165 arch/x86/include/asm/atomic.h <<arch_atomic_add_return>>static __always_inline int arch_atomic_add_return(int i, atomic_t *v)

??主要調(diào)查arm64的,該系列函數(shù)采用的是拼接定義的方法,如下:

arch/arm64/include/asm/atomic.hATOMIC_FETCH_OPS(atomic_add_return)#define ATOMIC_FETCH_OPS(op) \ATOMIC_FETCH_OP(_relaxed, op) \ATOMIC_FETCH_OP(_acquire, op) \ATOMIC_FETCH_OP(_release, op) \ATOMIC_FETCH_OP( , op)#define ATOMIC_FETCH_OP(name, op) \ static __always_inline int arch_##op##name(int i, atomic_t *v) \ { \return __lse_ll_sc_body(op##name, i, v); \ }

??以arch_atomic_add_return為例,宏展開(kāi)后,依次調(diào)用

__lse_ll_sc_body(atomic_add_return_relaxed, i, v); //i為將要累加的數(shù)值,v為atomic類型變量 __lse_ll_sc_body(atomic_add_return_acquire, i, v); __lse_ll_sc_body(atomic_add_return_release, i, v); __lse_ll_sc_body(atomic_add_return, i, v);

??__lse_ll_sc_body只定義在arm64下,其余架構(gòu)不支持,它的作用是給armv8.1的新feature:LSE(Large System Extensions) 提供支持,實(shí)現(xiàn)如下:

arch/arm64/include/asm/lse.h#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) #define __lse_ll_sc_body(op, ...) \ ({ \system_uses_lse_atomics() ? \__lse_##op(__VA_ARGS__) : \__ll_sc_##op(__VA_ARGS__); \ }) #else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ #define __lse_ll_sc_body(op, ...) __ll_sc_##op(__VA_ARGS__) #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */

??在配置了CONFIG_AS_LSE & CONFIG_ARM64_LSE_ATOMICS時(shí),通過(guò)調(diào)用system_uses_lse_atomics判斷cpu是否具備LSE能力。

static inline bool system_uses_lse_atomics(void) {return (static_branch_likely(&arm64_const_caps_ready)) &&static_branch_likely(&cpu_hwcap_keys[ARM64_HAS_LSE_ATOMICS]); }

??如果cpu具備LSE能力的話,就調(diào)用:

__lse_atomic_add_return_relaxed(i, v); __lse_atomic_add_return_acquire(i, v); __lse_atomic_add_return_release(i, v); __lse_atomic_add_return(i, v);

??否則調(diào)用:

__ll_sc_atomic_add_return_relaxed(i, v); __ll_sc_atomic_add_return_acquire(i, v); __ll_sc_atomic_add_return_release(i, v); __ll_sc_atomic_add_return(i, v);

??繼續(xù)查看__lse_atomic_add_return的定義,同樣采用的是拼接定義的方法,如下:

arch/arm64/include/asm/atomic_lse.h#define ATOMIC_OP_ADD_RETURN(name, mb, cl...) \ static inline int __lse_atomic_add_return##name(int i, atomic_t *v) \ { \u32 tmp; \\asm volatile( \__LSE_PREAMBLE \" ldadd" #mb " %w[i], %w[tmp], %[v]\n" \" add %w[i], %w[i], %w[tmp]" \: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \: "r" (v) \: cl); \\return i; \ }

??__lse_atomic_add_return##name是宏定義的展開(kāi)形式, 宏名稱為ATOMIC_OP_ADD_RETURN,定義_relaxed / _acquire / _release / ’ ’ 的位置如下:

ATOMIC_OP_ADD_RETURN(_relaxed, ) ATOMIC_OP_ADD_RETURN(_acquire, a, "memory") ATOMIC_OP_ADD_RETURN(_release, l, "memory") ATOMIC_OP_ADD_RETURN( , al, "memory")

??回過(guò)頭來(lái)看它的實(shí)現(xiàn)
??1) __LSE_PREAMBLE
????作用是告訴編譯器,下面的是lse指令。

#define __LSE_PREAMBLE ".arch_extension lse\n"

??2) ldadd
????通過(guò)一條指令完成,從內(nèi)存中取值,計(jì)算,存儲(chǔ)。

有關(guān)LSE參考另外一篇文章

小結(jié)

??atomic_add在arm64或x86平臺(tái)中使用的是atomic-instrumented.h中的定義,其它平臺(tái)使用的是atomic-fallback.h中的定義。

1.2.2 atomic_sub

static inline void atomic_sub(int i, atomic_t *v) {atomic_sub_return(i, v); }

總結(jié)

以上是生活随笔為你收集整理的Linux Kernel Atomic解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。