Atomare Operationen des Linux-Kernels

Dieser Artikel stellt hauptsächlich einige verwandte Verwendungen von atomaren Operationen vor.


Vorwort

        Dieser Artikel stellt hauptsächlich einige verwandte Verwendungen von atomaren Operationen vor.用于记录。  


1. Atomare Operationen

     Atomare Operationen garantieren, dass Änderungen an einer Ganzzahl exklusiv sind. Der Linux-Kernel stellt eine Reihe von Funktionen bereit, um atomare Operationen im Kernel zu implementieren.Diese Funktionen sind in zwei Kategorien unterteilt, die atomare Operationen auf Bit- bzw. Integer-Variablen ausführen. Atomare Operationen auf Bit- und Integer-Variablen beruhen alle auf atomaren Operationen auf der zugrunde liegenden CPU, sodass alle diese Funktionen eng mit der CPU-Architektur verbunden sind. Bei ARM-Prozessoren verwendet die zugrunde liegende Schicht LDREX- und STREX-Anweisungen. Beispielsweise ruft die zugrunde liegende Implementierung von atomic_inc() atomic_add() auf. Der Code lautet wie folgt:

static inline void atomic_add(int i, atomic_t *v)
{
    unsigned long tmp;
    int result;
    prefetchw(&v->counter);
    __asm__ __volatile__("@ atomic_add\n"
    "1:
    ldrex
    %0, [%3]\n"
    "
    add
    %0, %0, %4\n"
    "
    strex
    %1, %0, [%3]\n"
    "
    teq
    %1, #0\n"
    "
    bne
    1b"
    : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
    : "r" (&v->counter), "Ir" (i)
    : "cc");
}

        Der ldrex-Befehl ist mit strex gepaart, wodurch der Bus überwachen kann, ob es andere Entitäten gibt, die auf die Adresse zwischen ldrex und strex zugreifen.Wenn es einen gleichzeitigen Zugriff gibt, wird der Wert des ersten Registers auf 1 gesetzt, wenn der strex-Befehl ausgeführt wird (Non-Exclusive Access) und das Speicherverhalten ist ebenfalls erfolglos; wenn kein gleichzeitiger Zugriff vorliegt, setzt strex im ersten Register 0 (Exclusive Access) und das Speicherverhalten ist ebenfalls erfolgreich. Wenn in diesem Beispiel zwei gleichzeitige Entitäten gleichzeitig ldrex+strex aufrufen, wie in Abbildung 7.6 gezeigt, wird Strex von CPU0 zum Zeitpunkt T3 nicht ausgeführt, und zum Zeitpunkt T4 wird Strex von CPU1 erfolgreich ausgeführt. Daher wird nur CPU1 zwischen CPU0 und CPU1 erfolgreich ausgeführt, und die "teq%1, #0"-Beurteilungsaussage von CPU0, die Strex nicht ausführen konnte, wird nicht hergestellt, sodass CPU0, die fehlgeschlagen ist, erneut über "bne 1b" in ldrex eintritt. Dieser Prozess von ldrex und strex ist nicht nur auf die Parallelität zwischen mehreren Kernen anwendbar, sondern auch auf die Parallelität innerhalb desselben Kerns.

2. Ganzzahlige atomare Operationen

1. Legen Sie den Wert der atomaren Variablen fest

void atomic_set(atomic_t *v, int i);/*设置原子变量的值为 i*/
atomic_t v = ATOMIC_INIT(0);/*定义原子变量 v 并初始化为 0*/

2. Holen Sie sich den Wert der atomaren Variablen

atomic_read(atomic_t *v);/*返回原子变量的值 */

3. Addition und Subtraktion atomarer Variablen

void atomic_add(int i, atomic_t *v);/*原子变量增加 i*/
void atomic_sub(int i, atomic_t *v);/*原子变量减少 i*/

 4. Atomares Variableninkrement und -dekrement

void atomic_inc(atomic_t *v);/*原子变量增加1*/
void atomic_dec(atomic_t *v);/*原子变量减少1*/

5. Betrieb

int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i, atomic_t *v);
/*上述操作对原子变量执行自增、自减和减操作后(注意没有加),测试其是否为0,为0返回true,否
则返回false。*/
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
/*上述操作对原子变量进行加/减和自增/自减操作,并返回新的值。*/

3. Bitatomare Operation

 

1.设置位
void set_bit(nr, void *addr);
上述操作设置addr地址的第nr位,所谓设置位即是将位写为1。
2.清除位
void clear_bit(nr, void *addr);
上述操作清除addr地址的第nr位,所谓清除位即是将位写为0。
3.改变位
void change_bit(nr, void *addr);
上述操作对addr地址的第nr位进行反置。
4.测试位
test_bit(nr, void *addr);
上述操作返回addr地址的第nr位。
5.测试并操作位
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);
上述test_and_xxx_bit(nr,void*addr)操作等同于执行test_bit(nr,void*addr)后再执行
xxx_bit(nr,void*addr)。

Beispiel Verwenden Sie eine atomare Variable, damit ein Gerät nur von einem Prozess geöffnet wird

static atomic_t xxx_available = ATOMIC_INIT(1); /* 定义原子变量 */

static int xxx_open(struct inode *inode, struct file *filp)
{
   ...
 if (!atomic_dec_and_test(&xxx_available)) {
    atomic_inc(&xxx_available);
    return - EBUSY;
    /* 已经打开 */9 }
    ...
    return 0;
   /* 成功 */
}

static int xxx_release(struct inode *inode, struct file *filp)
{
  atomic_inc(&xxx_available);
  /* 释放设备 */
  return 0;
}

Guess you like

Origin blog.csdn.net/qq_48709036/article/details/124822656