Управление памятью модуля ядра Linux - PullRequest
2 голосов
/ 03 октября 2011

Я экспериментирую с управлением памятью в модулях ядра Linux, и мне было интересно, почему поток не видит ту же память, что и функции модуля.Я имею в виду, что

У меня есть int *x, объявленный глобально.Я выделяю пространство с помощью kmalloc и назначаю ему 10.Теперь, когда я пытаюсь получить доступ к нему из потока, я получаю совершенно другое значение.

Почему это происходит?Как мне обойти это?

РЕДАКТИРОВАТЬ:

Я запускаю свои программы в архитектуре x86 на одном ядре (на виртуальной машине).

Вот мой код: http://pastebin.com/94qGc6ZQ

Ответы [ 3 ]

2 голосов
/ 03 октября 2011

Вам нужна какая-то блокировка (и барьер памяти, который делает недействительным кеш).

В ядрах SMP реализованы механизмы блокировки (для ядра), которые позаботятся об этом:

Чтение http://www.mjmwired.net/kernel/Documentation/memory-barriers.txt и особенно "эффекты барьера межпроцессорной блокировки"

2 голосов
/ 03 октября 2011

В архитектурах SMP кэшируемые значения не обновляются для всех ядер, поэтому поток в другом ядре может использовать устаревшее значение.

Другая проблема, с которой вы можете столкнуться, - это одновременный доступ между потоками, что означает, что Поток 1 прочитал x, прежде чем Поток 2 смог записать x, но Поток 2 продолжил и сказал x = 10, но Поток 1 все еще использует старое значение, когда x был неинициализирован.

Способ решения второй проблемы (которая представляется более вероятной) состоит в использовании блокировки для контроля доступа к этой переменной, чтобы только 1 поток мог изменять / читать ее одновременно, чтобы избежать проблем с устаревшими значениями.

(Не аппаратный модуль ядра, поэтому не используйте volatile; P) используйте предложенные ниже значения smp_wb и smp_rb.

РЕДАКТИРОВАТЬ: Похоже, мое первое предложение было правильным. Так что для решения этой проблемы вы можете использовать smp_wb для x перед выполнением kmalloc и присваивания. Затем барьер для чтения на х, прежде чем пытаться напечатать значение х. Это фактически говорит ЦП о прочтении нового значения, поскольку оно может быть некорректным или могло быть переупорядочено при доступе. Возможно, вы сможете просто использовать барьер для чтения в другом потоке, но для безопасности используйте барьеры, где осуществляется доступ.

1 голос
/ 04 октября 2011

На какой архитектуре вы работаете?Я не верю другим ответам, в которых говорится, что вы сталкиваетесь с проблемами упорядочения памяти или проблемами когерентности кэша, потому что

  • x86 очень строго упорядочен, а kthread_run() внутренне принимает столько блокировок и т. Д.Я уверен, что есть эквивалент барьера памяти между присваиванием * x и началом вашего потока.Так что даже на более слабо упорядоченных архитектурах я не думаю, что вы действительно упускаете барьер памяти.
  • Я не верю, что есть любая архитектура, в которой работает Linux, которая не связана с кэшеммежду процессорами.Вы должны быть осторожны с внешними устройствами, делающими DMA в память, но это совершенно не похоже на проблему здесь.

Другими словами, я думаю, что код, который вы написали в своем вопросе, выглядит нормально.Я подозреваю, что это сводится к реальному коду, и тем самым вы избавились от настоящей ошибки.

Конечно, если у вас есть код, который изменяет переменную, используемую в вашем потоке, это действительно так после kthread_run у вас возникает состояние гонки, которое может привести к ошибке, подобной той, что вы видите здесь.

...