Действительно ли SCHED_IDLE исключает выполнение на не простоях ядра? - PullRequest
4 голосов
/ 01 апреля 2019

Я пытаюсь реализовать непривилегированный тестовый пример для неограниченной инверсии приоритетов при отсутствии мьютексов наследования приоритетов, используя SCHED_IDLE.Тест работает с SCHED_FIFO и различными приоритетами в реальном времени (взаимоблокировка для мьютекса не-PI, немедленное разрешение с помощью мьютекса PI), но чтобы включить его в набор тестов, который будет работать без прав в реальном времени, я бы хотел вместо этого использовать SCHED_IDLEпричем потоки «среднего» и «высокого» приоритетов равны SCHED_OTHER (в этом случае это не совсем приоритет «инверсия», но концепция все еще должна работать - «средний» должен исключать выполнение «низкого»)).

К сожалению, в тесте не удается провести различие между мьютексами PI и не-PI;это продвигает прогресс в любом случае.Очевидно, задача SCHED_IDLE выполняется, даже если есть другая выполняемая задача.Сходство с процессором было установлено так, чтобы связать их все с одним и тем же ядром, чтобы задача с низким приоритетом не могла перейти на другое ядро ​​для запуска.И я знаю, что задачи SCHED_IDLE должны выполняться с повышенными привилегиями в то время как в пространстве ядра, чтобы предотвратить инверсию приоритетов пространства ядра, поэтому я попытался убедиться, что «низкий» поток не входит в пространство ядра, делая его занятым циклом вuserspace, и strace не показывает никаких признаков того, что он делает системный вызов в то время, когда он не должен продвигаться вперед.

Позволяет ли SCHED_IDLE Linux просто запускать бездействующие задачи, когда ядро ​​фактически не находится в режиме ожидания?Или есть что-то еще, что я мог бы упустить?

Вот тестовый код, слегка адаптированный для того, чтобы его можно было запускать либо в режиме реального времени, либо SCHED_IDLE:

#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>

sem_t sem;

void *start1(void *p)
{
    pthread_mutex_lock(p);
    sem_post(&sem);
    sem_post(&sem);
    usleep(100000);
    pthread_mutex_unlock(p);
    return 0;
}

void *start2(void *p)
{
    sem_wait(&sem);
    time_t t0 = time(0);
    while (pthread_mutex_trylock(p)) {
        if (time(0)>t0+5) return 0;
    }
    pthread_mutex_unlock(p);
    return 0;
}

void *start3(void *p)
{
    sem_wait(&sem);
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += 5;
    int r;
    if (r=pthread_mutex_timedlock(p, &ts)) {
        printf("failed: %d %s\n", r, strerror(r));
    } else {
        pthread_mutex_unlock(p);
    }
    return 0;
}

int main(int argc, char **argv)
{
    int policy = argc>1 ? SCHED_IDLE : SCHED_FIFO;
    int a = sched_get_priority_min(policy);
    pthread_attr_t attr;
    pthread_t t1,t2,t3;
    struct sched_param param = {0};

    cpu_set_t set = {0};
    CPU_ZERO(&set);
    CPU_SET(0, &set);
    pthread_setaffinity_np(pthread_self(), sizeof set, &set);

    pthread_attr_init(&attr);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&attr, policy);

    pthread_mutexattr_t ma;
    pthread_mutexattr_init(&ma);
    pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);
    pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, &ma);

    sem_init(&sem, 0, 0);

    param.sched_priority = a+1;
    pthread_attr_setschedparam(&attr, &param);
    if (pthread_create(&t2, policy==SCHED_IDLE ? 0 : &attr, start2, &mtx)) return 1;

    param.sched_priority = a+2;
    pthread_attr_setschedparam(&attr, &param);
    if (pthread_create(&t3, policy==SCHED_IDLE ? 0 : &attr, start3, &mtx)) return 1;

    param.sched_priority = a;
    pthread_attr_setschedparam(&attr, &param);
    if (pthread_create(&t1, &attr, start1, &mtx)) return 1;

    pthread_join(t1, 0);
    pthread_join(t2, 0);
    pthread_join(t3, 0);
    return 0;
}

1 Ответ

1 голос
/ 04 апреля 2019

Позволяет ли Linux SCHED_IDLE просто запускать бездействующие задачи, когда ядро на самом деле не простаивает? Или я могу что-то пропустить?

Это правильно. SCHED_IDLE дает задачам очень низкое, но ненулевое взвешивание - примерно на 70% меньше процессорного времени, чем у хорошей задачи 19.

...