Подскажите пожайлуста как связать PID TSS и CPU affinity mask

Тема в разделе "WASM.BEGINNERS", создана пользователем Tracker, 24 мар 2008.

  1. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    Полазил по интернету. Скачял мануалы с Intel.com, но возможно знания аглийского до конца не хватает понять.
    Как связать TSS и CPU affinity mask?
    Каким образом PID процесса связывается с процесcором через Sheduler?
    Где хранится CPU affinity mask или в какой дескриптор входит?
    Перекопал исходники Линукса на предмет как это работает, но не нашел.
    sched_setaffinity,
    sched_getaffinity,
    CPU_CLR,
    CPU_ISSET,
    CPU_SET,
    CPU_ZERO
    Помогите разобраться.
     
  2. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    каша в голове. советую разобратся с базовыми понятиями.
     
  3. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
  4. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    они никак не связаны
    значение PID находится в дескрипторе процесса struct task_struct
    каждый CPU имеет ассоциированную с ним очередь выполнения runqueues типа struct rq
    (runqueus является per-cpu переменной)
    каждая очередь выполнения имеет связный список дескрипторов struct task_struct
    вот и вся связь
    struct task_struct
    плохо искал ;)
     
  5. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    Спасибо за ответ rei3er
    Я данную структуру нашел. Разбираться с sheduler-ом не простая задача.
    Вы правильно меня поняли.
    Хочу немного пояснить свой вопрос:


    Как указать процессу исполняться на определённом ядре процессора либо на определённом процессоре без вызова системных функций sched_getaffinity и
    sched_setaffinity?


    Если посмотреть здесь часть "Модуль управления сегментами в Linux"
    http://www.interface.ru/home.asp?artId=2814
    Каждый дескриптор сегмента TSS указывает на отдельный процесс. TSS хранит информацию об аппаратном контексте для каждого CPU, который принимает участие в переключении контекста. Например, при переключении режимов U->K x86 CPU получает адрес стека режима ядра из TSS.
    Каждый процесс имеет свой собственный TSS-дескриптор, хранящийся в GDT.


    Идем по списку исходников
    вот здесь удобно http://lxr.linux.no/linux/include/linux/sched.h#L937

    long sched_getaffinity(pid_t pid, cpumask_t *mask)
    4497{
    4498 struct task_struct *p;
    4499 int retval;
    4500
    4501 mutex_lock(&sched_hotcpu_mutex);
    4502 read_lock(&tasklist_lock);
    4503
    4504 retval = -ESRCH;
    4505 p = find_process_by_pid(pid);
    4506 if (!p)
    4507 goto out_unlock;
    4508
    4509 retval = security_task_getscheduler(p);
    4510 if (retval)
    4511 goto out_unlock;
    4512
    4513 cpus_and(*mask, p->cpus_allowed, cpu_online_map);
    4514
    4515out_unlock:
    4516 read_unlock(&tasklist_lock);
    4517 mutex_unlock(&sched_hotcpu_mutex);
    4518
    4519 return retval;
    4520}

    long sched_setaffinity(pid_t pid, cpumask_t new_mask)
    4406{
    4407 cpumask_t cpus_allowed;
    4408 struct task_struct *p;
    4409 int retval;
    4410
    4411 mutex_lock(&sched_hotcpu_mutex);
    4412 read_lock(&tasklist_lock);
    4413
    4414 p = find_process_by_pid(pid);
    4415 if (!p) {
    4416 read_unlock(&tasklist_lock);
    4417 mutex_unlock(&sched_hotcpu_mutex);
    4418 return -ESRCH;
    4419 }
    4420
    4421 /*
    4422 * It is not safe to call set_cpus_allowed with the
    4423 * tasklist_lock held. We will bump the task_struct's
    4424 * usage count and then drop tasklist_lock.
    4425 */
    4426 get_task_struct(p);
    4427 read_unlock(&tasklist_lock);
    4428
    4429 retval = -EPERM;
    4430 if ((current->euid != p->euid) && (current->euid != p->uid) &&
    4431 !capable(CAP_SYS_NICE))
    4432 goto out_unlock;
    4433
    4434 retval = security_task_setscheduler(p, 0, NULL);
    4435 if (retval)
    4436 goto out_unlock;
    4437
    4438 cpus_allowed = cpuset_cpus_allowed(p);
    4439 cpus_and(new_mask, new_mask, cpus_allowed);
    4440 retval = set_cpus_allowed(p, new_mask);
    4441
    4442out_unlock:
    4443 put_task_struct(p);
    4444 mutex_unlock(&sched_hotcpu_mutex);
    4445 return retval;
    4446}

    Это только верхушка айсберга и реализует Software affinity.
     
  6. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    6.9.2 Сегменты в 80386

    Сегментные регистры используются при трансляции адреса для генерации линейного адреса из логического (виртуального) адреса.

    linear_address = segment_base + logical_address

    Линейный адрес транслируется затем в физический адрес посредством аппаратуры страничной организации (paging)

    Каждый сегмент в системе описан 8-ми байтным дескриптором сегмента, в котором содержится вся необходимая информация (база, ограничение, тип, привилегии).

    Имеют место следующие сегменты:

    Обычные сегменты
    сегменты кода и данных

    Системные сегменты
    (TSS) cегменты состояния задачи
    (LDT) таблицы локальных дескрипторов

    Характеристики системных сегментов:

    * Системные сегменты являются спецификаторами задач
    * Имеется TSS, связанный с каждой задачей в системе. Он содержит tss_struct (sched.h). Размер этого сегмента соответствует размеру tss_struct, исключая i387_union (232 байта). Он содержит всю информацию, необходимую для перезапуска задачи.
    * Таблицы LDT содержат дескрипторы обычных сегментов, принадлежащих задаче. В Linux каждой задаче соответствует одна LDT. B Linux task_struct предусмотрено пространство для 32-х дескрипторов. Обычная LDT, созданная в Linux, имеет размер 24 байта и, следовательно, пространство для 3-х входов. Ее содержимое:

    * LDT[0] Null (принудительно)
    * LDT[1] дескриптора сегмента пользовательского кода
    * LDT[2] дескриптор сегмента пользовательских данных/стека

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

    Для получения доступа ко всем этим сегментам 386 использует таблицу глобальных дескрипторов (GDT), которая устанавливается в памяти системой (местоположение задается регистром GDT). GDT содержит дескрипторы сегментов для каждого сегмента состоян ия задачи, каждого локального дескриптора и обычных сегментов. Linux GDT содержит входы двух обыкновенных сегментов:

    * GDT[0] нулевой дескриптор
    * GDT[1] дескриптор сегмента кода ядра
    * GDT[2] дескриптор сегмента данных/стека ядра

    Оставшаяся область GDT заполнена TSS и LDT дескрипторами системы.

    * GDT[3] ???
    * GDT[4] = TSS0, GDT[5] = LDT0
    * GDT[6] = TSS1, GDT[7] = LDT1

    ..... и т.д......

    Заметьте LDT[n] != LDTn

    * LDT[n] = n-й дескриптор в LDT текущей задачи
    * LDTn = дескриптор в GDT для LDT n-й задачи

    В данном случае GDT имеет 256 входов, пространство для 126 задач. Сегменты ядра имеют базу 0хс0000000, которая задает местонахождение ядра в линейном представлении. Прежде, чем сегмент может быть использован, содержимое дескриптора для этого сегмента должно быть загружено в сегментный регистр. 386 имеет множество сложных критериев, ограничивающих доступ к сегментам, так что вы не сможете просто загрузить дескриптор в сегментный регистр. Также эти сегментные регистры имеют невидимые для программиста участки. Видимые участки - это то, что обычно называется сегментными регистрами cs, ds, es, fs, gs и ss.

    Программист загружает один из этих регистров 16-ти битным значением, называемым селектором. Селектор однозначно идентифицирует дескриптор сегмента в одной из таблиц. Доступ подтверждается и соответствующий дескриптор загружается посредством аппар атных средств.

    Обычно в Linux игнорируется комплексная защита на уровне сегмента (чрезмерная?), предоставляемая 386. Она базируется на основе аппаратных средств страничной организации и объединенной защитой на уровне страницы. Правила на уровне сегмента, которые применяются к пользовательским процессам, состоят в следующем:

    1. Процесс не может напрямую обращаться к данным ядра или сегментам кода.
    2. Всегда имеет место контроль ограничения, однако, условие, что каждый

    Здесь уже ближе к процессору
    http://lxr.linux.no/linux/include/asm-i386/processor.h#L275
     
  7. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    здесь под процессом понимается задача в контексте архитектуры IA-32, а не ОС

    по поводу исходников
    что непонятно?
     
  8. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    Мне не понятно как на уровне ассемблера сделать тоже самое, а именно указать какая задача в контексте IA32 на каком процессорном ядре будет выполнятся?
    Как скажем в ассемблере указать что задача из данного TSS сегмента на ядро 1, а задача из того TSS сегмента на ядро 2?
     
  9. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    Tracker
    тут уже правильно посоветовали, разберитесь с терминами
    если дело касается Linux, то TSS представлен per-cpu переменной init_tss
    она используется совместно всеми процессами, которые последовательно выполняются на соответствующем процессоре
    привязка процесса к процессорам (cpus_allowed в struct task_struct) происходит в трех случаях
    1. создание процесса (cpus_allowed наследуется от родительского процесса)
    2. баллансировка нагрузки (перераспределение процессов по очередям выполнения (а значит по процессорам) для равномерной загрузки каждого процессора)
    3. sched_setaffinity() через миграционные процесс
     
  10. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    Я вот не понимаю до конца как работает многоядерный процессор (Core2Duo,Core2Quad)?
    Каким образом достигается обработка отдельной задачи на разных ядрах или на одном?

    Linux не при чем. Это как пример был который легко посмотреть в исходниках.
    Вопрос звучит так:
    Я не пишу свою ОС, но хочу понимать каким образом я могу перейти в защищенный режим, создать несколько задачь и заставить их выполняться на раличных ядрах без загрузки сторонней ОС (Windows, Linux)?
    Простой примитивный пример.
     
  11. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    5.1.32. В случае SMP запускаем другие процессоры

    Выполнение smp_init(), в зависимости от конфигурации ядра, возможно тремя способами.

    Для однопроцессорных (UP) систем без IO APIC (CONFIG_X86_IO_APIC не определена), smp_init() пуста - соответственно ничего не происходит.

    Для однопроцессорных UP систем с IO APIC для маршрутизации прерываний она вызывает IO_APIC_init_uniprocessor().

    Для многопроцессорных (SMP) систем ее основная задача заключается в вызове архитектурно-специфичной функции "smp_boot_cpus()", которая выолняет следующее:

    - Для ядер с CONFIG_MTRR вызывает mtrr_init_boot_cpu(), которая должна отработать до того, как загрузятся другие процессоры.

    - Сохраняет и выводит информацию о BSP CPU.

    - Сохраняет ID BSP APIC и BSP ID логического CPU (последний равен 0).

    - Если не найдена таблица маршрутизации прерываний MP BIOS, то возвращается к использованию только одного CPU и завершается.

    - Проверяет существование локального APIC для BSP.

    - Если использована опция загрузки "maxcpus" со значением 1 (без SMP), то игнорирует таблицу маршрутизации прерываний MP BIOS.

    - Переключает систему из PIC-режима в режим прерывания симметричного ввода-вывода.

    - Устанавливает локальный APIC BSP.

    - Использует карту наличия (presence map) CPU для последовательной загрузки AP. Ожидает загрузки предыдущего AP перед запуском загрузки следующего.

    - В случае использования IO APIC {что справедливо всегда кроме случаев с опцией загрузки "noapic"} устанавливает IO APIC (или каждый, если их несколько).

    http://linuxportal.ru/entry.php/1506_0_3_0_C/
     
  12. Tracker

    Tracker New Member

    Публикаций:
    0
    Регистрация:
    24 мар 2008
    Сообщения:
    9
    Докопался до сюда в исходниках. Есть вменяемые доки по IO APIC?
    http://www.cs.uwaterloo.ca/~brecht/servers/apic/SMP-affinity.txt

    static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
    293{
    294 struct irq_cfg *cfg = irq_cfg + irq;
    295 unsigned long flags;
    296 unsigned int dest;
    297 cpumask_t tmp;
    298
    299 cpus_and(tmp, mask, cpu_online_map);
    300 if (cpus_empty(tmp))
    301 return;
    302
    303 if (assign_irq_vector(irq, mask))
    304 return;
    305
    306 cpus_and(tmp, cfg->domain, mask);
    307 dest = cpu_mask_to_apicid(tmp);
    308
    309 /*
    310 * Only the high 8 bits are valid.
    311 */
    312 dest = SET_APIC_LOGICAL_ID(dest);
    313
    314 spin_lock_irqsave(&ioapic_lock, flags);
    315 __target_IO_APIC_irq(irq, dest, cfg->vector);
    316 irq_desc[irq].affinity = mask;
    317 spin_unlock_irqrestore(&ioapic_lock, flags);
    318}