Я читаю linux kernel implementation из дважды связанного списка. Я не понимаю использование макроса WRITE_ONCE(x, val)
. Он определяется следующим образом в compiler.h:
#define WRITE_ONCE(x, val) x=(val)
Он используется семь раз в файле, например
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
WRITE_ONCE(prev->next, new);
}
Я читал, что он используется для предотвращения условий гонки.
У меня есть два вопроса:
1/Я думал, что макрос заменяется кодом во время компиляции. Итак, как этот код отличается от следующего? Как этот макрос может избежать условий гонки?
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
2/Как узнать, когда мы должны его использовать? Например, он используется для __lst_add()
, но не для __lst_splice()
:
static inline void __list_splice(const struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
Редактирование:
Вот сообщение фиксации относительно этого файла и WRITE_ONCE
, но это не помогает мне ничего понять...
: используйте WRITE_ONCE() при инициализации структур list_head
Кодекс, который делает бесконтактное тестирование пустоты не-RCU-списков, полагается на INIT_LIST_HEAD(), чтобы написать заголовок списка → следующий указатель атомарно, особенно когда INIT_LIST_HEAD() вызывается из list_del_init(). Поэтому это commit добавляет WRITE_ONCE() к этому хранилища указателей функций, которые могут повлиять на головку → следующий указатель.