Идентификация потоков ядра

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

Я обнаружил, что потоки ядра не имеют собственной памяти, поэтому значения Vm * в /proc/ $pid/status отсутствуют, а stat on/proc/$pid/exe ничего не возвращает.

Итак, я решил, что могу идентифицировать потоки ядра, если процесс не имеет значений Vm * и не имеет номера inode. Я ошибался... мой script видит процессы php-cgi, которые когда-то идентифицируются как процессы ядра.

Если окажется, что большинство из этих неправильно идентифицированных процессов - это зомби, которые ушли через секунду. Поэтому я выполнил простую проверку, чтобы узнать, является ли статус "Z". Если это так, игнорируйте его. Это избавило меня от множества ложных срабатываний, но все же я получаю сообщения о процессах ядра php-cgi.

Может ли кто-нибудь сказать мне, как я могу отличить поток ядра от пользовательского потока правильно?

Ответ 1

Есть некоторые видимые различия между потоком ядра и потоком пользовательского пространства:

  • /proc/$pid/cmdline пуст для потоков ядра - это метод, используемый ps и top для различения потоков ядра.

  • Символьная ссылка /proc/$pid/exe не имеет цели для потоков ядра - это имеет смысл, поскольку у них нет соответствующего исполняемого файла в файловой системе.

    В частности, системный вызов readlink() возвращает ENOENT ( "Нет такого файла или каталога" ), несмотря на то, что сама ссылка существует, чтобы обозначить тот факт, что исполняемый файл для этого процесса не существует (и никогда не был).

    Поэтому надежным способом проверки потоков ядра должно быть вызов readlink() на /proc/$pid/exe и проверка его кода возврата. Если это удается, то $pid является пользовательским процессом. Если с ENOENT он терпит неудачу, дополнительный stat() на /proc/$pid/exe должен отличать случай от потока ядра от только что завершившегося процесса.

  • /proc/$pid/status отсутствует несколько полей для большинства потоков ядра - более конкретно несколько полей, связанных с виртуальной памятью.

Ответ 2

Как вы указали в своем собственном комментарии выше, все пользовательские процессы являются потомками процесса init (pid = 1). Нити ядра не являются потомками процесса init, поскольку init - это пользовательский процесс, и пользовательские процессы не могут создавать потоки ядра. Поэтому, чтобы проверить, является ли процесс p пользовательским процессом, а не потоком ядра, нужно работать на графике процесса и оценить, если init dom p где dom является Dominator. Конкретно в Python:

def is_user_process(p):
  if (p=='1'):
    print 'User process'
  else:
    pstat = open('/proc/%s/stat'%p).read().split()
    parent = pstat[3]
    if (parent=='1'):
      print 'User process'
    elif (parent=='0'):
      print 'Kernel thread'
    else:
      is_user_process(parent)

Ответ 3

Вот версия, которая работает под bash:

# check if pid is user process and not a kernel thread
is_user_process() {
  if [[ $1 -eq 1 ]]; then
    return 0
  else
    parent=$(grep -e '^PPid:' /proc/$1/status | cut -c6-)
    if [[ $parent -eq 1 ]]; then
      return 0
    elif [[ $parent -eq 0 ]]; then
      return 1
    else
      is_user_process $parent
    fi
  fi
}

Чтобы использовать его,

~$ is_user_process `pgrep kthreadd` || echo "kthreadd is kernel process"

Это было первое полезное решение для меня, по крайней мере, спасибо за er0 версии python.