Мах, планирующий и интерфейсы потока

OS X основывается на Махе и BSD. Как Мах и большая часть BSD системы UNIX, это содержит усовершенствованный планировщик на основе Маха CMU 3 планировщика. В этой главе описываются планировщик и с точки зрения программиста ядра и с точки зрения разработчика приложений, пытающегося установить параметры планирования.

Эта глава начинается с Обзора Планирования, описывающего фундаментальные понятия позади Маха, планирующего на высоком уровне, включая приоритетную поддержку в реальном времени.

Второй раздел, Используя Маха, Планирующего От Пользовательских приложений, описывает, как получить доступ к определенному ключу подпрограммы планировщика Маха от пользовательских приложений и от других частей ядра вне планировщика.

Третий раздел, Поток ядра APIs, объясняет связанные с планировщиком темы включая то, как создать и завершить потоки ядра и описывает BSD spl макросы и их ограниченная полноценность в OS X.

Обзор планирования

Планировщик OS X получен из планировщика, используемого в OSFMK 7.3. В целом много документации о предшествующих реализациях применяется к планировщику в OS X, несмотря на то, что Вы найдете многочисленные различия. Подробные данные тех различий выходят за рамки этого обзора.

Мах, планирующий, основывается на системе выполненных очередей в различных приоритетах, обрабатывающихся по-разному. Приоритетные уровни разделены на четыре полосы согласно их характеристикам, как описано в Таблице 10-1.

Табличные 10-1  приоритетные полосы Потока

Приоритетная полоса

Характеристики

Нормальный

нормальные приоритеты потока приложения

Системный высокий приоритет

потоки, приоритет которых был повышен выше нормальных потоков

Привилегированный режим только

зарезервированный для потоков, создаваемых в ядре, которое должно работать в более высоком приоритете, чем все потоки пространства пользователя (Набор I/O workloops, например)

Потоки в реальном времени

потоки, приоритет которых основывается на получении четко определенной части общих тактов, независимо от другого действия (в приложении аудиоплеера, например).

Потоки могут мигрировать между приоритетными уровнями по ряду причин, в основном как артефакт используемого алгоритма разделения времени. Однако эта миграция в данной полосе.

Потоки, отмеченные как являющийся приоритетом в реальном времени, являются также особенными в глазах планировщика. Поток в реальном времени говорит планировщику, что это должно работать за A циклы из следующего B циклы. Например, это, возможно, должно было бы работать за 3 000 из следующих 7 000 тактов для поддержания на высоком уровне. Это также говорит планировщик, должны ли те циклы быть непрерывными. Используя длинные непрерывные кванты обычно осуждается, но иногда необходим для специализированных приложений реального времени.

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

Изменение приоритета потока превратить его в приоритетный поток в реальном времени с помощью вызовов Маха описано более подробно в Использовании Маха, Планирующего От Пользовательских приложений.

В дополнение к сырым данным Мах интерфейсы RPC некоторыми аспектами приоритета потока можно управлять от пространства пользователя с помощью приоритета потока POSIX API. Поток POSIX API в состоянии установить приоритет потока только в самой низкой приоритетной полосе (0–63). Для получения дополнительной информации о приоритете потока POSIX API посмотрите Используя pthreads API для Влияния на Планирование.

Почему изменялся мой приоритет потока?

Существует много причин, что может измениться приоритет потока. Этот раздел пытается объяснить первопричину этих приоритетных изменений потока.

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

Потоки, которые являются в большой степени, вычисляют ограниченный, отданы более низкий приоритет, чтобы помочь минимизировать время отклика для интерактивных задач так, чтобы высокий приоритет вычислил ограниченные потоки, не может монополизировать систему и предотвратить более низкий приоритет потоки I/O-bound от выполнения. Даже в более низком приоритете, вычисление ограниченных потоков все еще часто работает, начиная с более высокого приоритета потоки I/O-bound делают только небольшое количество обработки, блока на I/O снова, затем позволяют вычислению ограниченных потоков выполняться.

Все эти механизмы работают постоянно в планировщике Маха. Это означает, что потоки часто перемещаются вверх или вниз в приоритете, основанном на их поведении и поведении других потоков в системе.

Используя Маха, планирующего от пользовательских приложений

Существует три основных способа измениться, как планируется пользовательский поток. Можно использовать BSD pthreads API для изменения базовой политики и важности. Можно также использовать вызовы RPC Маха для изменения важности задачи. Наконец, можно использовать вызовы RPC для изменения политики планирования переместить поток в различную полосу планирования. Это обычно используется при взаимодействии с CoreAudio.

pthreads API является пространством пользователя API и ограничил уместность для программистов ядра. Поток Маха и задача APIs является более общим и может использоваться отовсюду в ядре. Поток Маха и вызовы задачи можно также вызвать от пользовательских приложений.

Используя pthreads API для влияния на планирование

OS X поддерживает много политик на уровне API потоков POSIX. При необходимости в поведении в реальном времени необходимо использовать Маха thread_policy_set вызвать. Это описано в Использовании Потока Маха API для Влияния на Планирование.

pthreads API корректирует приоритет потоков в данной задаче. Это не обязательно влияет на производительность относительно потоков в других задачах. Для увеличения приоритета задачи можно использовать nice или renice из командной строки или вызова getpriority и setpriority из Вашего приложения.

API обеспечивает две функции: pthread_getschedparam и pthread_setschedparam. Их прототипы похожи на это:

pthread_setschedparam(pthread_t thread, int policy,
        struct sched_param *param);
pthread_getschedparam(pthread_t thread, int *policy,
        struct sched_param *param)

Параметры за pthread_getschedparam являются прямыми. Первым параметром является поток ID, и другие - указатели на память, где будут сохранены результаты.

Параметры pthread_setschedparam не так очевидны, как бы то ни было. Как с pthread_getschedparam, первым параметром является поток ID.

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

Третьим параметром является структура, содержащая различные параметры планирования.

Вот основной пример использования pthreads функции для установки политики и приоритета планирования потока.

int set_my_thread_priority(int priority) {
    struct sched_param sp;
 
    memset(&sp, 0, sizeof(struct sched_param));
    sp.sched_priority=priority;
    if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp)  == -1) {
        printf("Failed to change priority.\n");
        return -1;
    }
    return 0;
}

Этот фрагмент кода устанавливает политику планирования для текущего потока к циклическому планированию и устанавливает относительную важность потока в задаче к значению, переданному в через priority параметр.

Для получения дополнительной информации см. страницу руководства для pthread.

Используя поток Маха API для влияния на планирование

Этот API часто используется в мультимедийных приложениях для получения приоритета в реальном времени. Это также полезно в других ситуациях когда pthread планирование API не может использоваться или не обеспечивает необходимую функциональность.

API состоит из двух функций, thread_policy_set и thread_policy_get.

kern_return_t thread_policy_set(
                thread_act_t thread,
                thread_policy_flavor_t flavor,
                thread_policy_t policy_info,
                mach_msg_type_number_t count);
 
kern_return_t thread_policy_get(
                thread_act_t thread,
                thread_policy_flavor_t flavor,
                thread_policy_t policy_info,
                mach_msg_type_number_t *count,
                boolean_t *get_default);

Параметры этих функций являются примерно тем же, за исключением того, что thread_policy_get функция берет указатели для count и get_default параметры. Количество inout параметр, означая, что это интерпретируется как максимальная сумма хранения (в модулях int32_t) то, что задача вызова выделила для возврата, но это также перезаписывается планировщиком для указания фактически возвращенного объема данных.

Эти функции получают и устанавливают несколько параметров, согласно выбранной политике потока. Возможные политики потока перечислены в Таблице 10-2.

Табличные 10-2  политики Потока

Политика

Значение

THREAD_STANDARD_POLICY

Значение по умолчанию

THREAD_TIME_CONSTRAINT_POLICY

Используемый для указания поведения в реальном времени.

THREAD_PRECEDENCE_POLICY

Используемый для указания важности вычисления относительно других потоков в данной задаче.

Следующий фрагмент кода показывает, как установить приоритет задачи сказать планировщику, что этому нужна производительность в реальном времени. Значения в качестве примера, предоставленные в комментариях, основываются на предполагаемых потребностях esd (демон Esound).

#include <mach/mach_init.h>
#include <mach/thread_policy.h>
#include <mach/sched.h>
#include <pthread.h>
 
int set_realtime(int period, int computation, int constraint) {
    struct thread_time_constraint_policy ttcpolicy;
    int ret;
    thread_port_t threadport = pthread_mach_thread_np(pthread_self());
 
    ttcpolicy.period=period; // HZ/160
    ttcpolicy.computation=computation; // HZ/3300;
    ttcpolicy.constraint=constraint; // HZ/2200;
    ttcpolicy.preemptible=1;
 
    if ((ret=thread_policy_set(threadport,
        THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&ttcpolicy,
        THREAD_TIME_CONSTRAINT_POLICY_COUNT)) != KERN_SUCCESS) {
            fprintf(stderr, "set_realtime() failed.\n");
            return 0;
    }
    return 1;
}

Временные стоимости являются с точки зрения Маха абсолютными единицами измерения времени. Так как эти значения расходятся в различном CPUs, необходимо обычно использовать числа относительно HZ (глобальная переменная в ядре, содержащем текущее число галочек в секунду). Можно или обработать это преобразование сами путем деления этого значения на надлежащее количество или использовать подпрограммы преобразования, описанные в Использовании Абстракций Времени Ядра.

Скажите свои компьютерные отчеты 133 миллиона для значения HZ. При передаче значений в качестве примера, данных как параметры этой функции поток говорит планировщику, что этому нужны приблизительно 40 000 (HZ/3300) из следующих 833,333 (HZ/160) циклы шины. preemptible значение (1) указывает, что те 40 000 циклов шины не должны быть непрерывными. Однако constraint значение (HZ/2200) говорит планировщику, что может быть не больше, чем 60 000 циклов шины между запуском вычисления и концом вычисления.

Прямым примером с помощью этого API является код, выводящий на экран видео непосредственно к аппаратным средствам кадрового буфера. Это должно выполнить для определенного числа циклов каждый кадр для получения новых данных в кадровый буфер. Это может быть прервано без беспокойства, но если это прервано слишком долго, видеооборудование начинает отображать устаревший кадр, прежде чем программное обеспечение запишет обновленные данные, приводя к противному незначительному сбою. Аудио имеет подобное поведение, но так как это обычно буферизуется по пути (в аппаратных средствах и в программном обеспечении), существует больший допуск для изменений в синхронизации к точке.

Другой вызов политики THREAD_PRECEDENCE_POLICY. Это используется для установки относительной важности потоков нев реальном времени. Ее соглашение о вызовах подобно, за исключением того, что ее структура thread_precedence_policy, и содержит только одно поле, integer_t вызванный importance. В то время как это - 32-разрядное значение со знаком, минимальное юридическое значение является нулем (IDLE_PRI). набор потоков к IDLE_PRI когда никакой другой поток, как не будут планировать, выполнится, только выполнится.

В целом большие значения указывают более высокий приоритет. Максимальный предел подвержен изменениям, как приоритетные полосы, некоторые из которых имеют особое назначение (такое как потоки в реальном времени). Таким образом, в целом, необходимо использовать pthreads APIs для достижения этой функциональности вместо того, чтобы использовать эту политику непосредственно, если Вы не настраиваете неактивный поток.

Используя задачу Маха API для влияния на планирование

Этот относительно простой API не особенно полезен для большинства разработчиков. Однако это может быть выгодно при разработке графического интерфейса пользователя для Дарвина. Это также обеспечивает некоторое понимание установления приоритетов задач в OS X. Это представлено здесь для полноты.

API состоит из двух функций, task_policy_set и task_policy_get.

kern_return_t task_policy_set(
                task_t task,
                task_policy_flavor_t flavor,
                task_policy_t policy_info,
                mach_msg_type_number_t count);
 
kern_return_t task_policy_get(
                task_t task,
                task_policy_flavor_t flavor,
                task_policy_t policy_info,
                mach_msg_type_number_t *count,
                boolean_t *get_default);

Как с thread_policy_set и thread_policy_get, параметры подобны, за исключением того, что task_policy_get функция берет указатели для count и get_default параметры. count параметр inout параметр. Это интерпретируется как максимальная сумма хранения, которое задача вызова выделила для возврата, но это также перезаписывается планировщиком для указания фактически возвращенного объема данных.

Эти функции получают и устанавливают единственный параметр, ту из роли данной задачи, изменяющей способ, которым приоритет задачи изменяется в течение долгого времени. Возможные роли задачи перечислены в Таблице 10-3.

Табличные 10-3  роли Задачи

Роль

Значение

TASK_UNSPECIFIED

Значение по умолчанию

TASK_RENICED

Когда процесс выполняется с, это установлено nice или изменяется renice.

TASK_FOREGROUND_APPLICATION

Приложение GUI на переднем плане. Может быть больше чем одно приоритетное приложение.

TASK_BACKGROUND_APPLICATION

Приложение GUI в фоновом режиме.

TASK_CONTROL_APPLICATION

Зарезервированный для прикрепления или эквивалентный (присвоил FCFS).

TASK_GRAPHICS_SERVER

Зарезервированный для WindowServer или эквивалентный (присвоил FCFS).

Следующий фрагмент кода показывает, как установить приоритет задачи сказать планировщику, что это - приоритетное приложение (независимо от того, является ли это действительно).

#include <mach/mach_init.h>
#include <mach/task_policy.h>
#include <mach/sched.h>
 
int set_my_task_policy(void) {
    int ret;
    struct task_category_policy tcatpolicy;
 
    tcatpolicy.role = TASK_FOREGROUND_APPLICATION;
 
    if ((ret=task_policy_set(mach_task_self(),
        TASK_CATEGORY_POLICY, (thread_policy_t)&tcatpolicy,
        TASK_CATEGORY_POLICY_COUNT)) != KERN_SUCCESS) {
            fprintf(stderr, "set_my_task_policy() failed.\n");
            return 0;
    }
    return 1;
}

Поток ядра APIs

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

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

Создание и уничтожение потоков ядра

Рекомендуемый интерфейс для создания потоков в ядре через Набор I/O. Это обеспечивает IOCreateThread, IOThreadSelf, и IOExitThread функции, делающие его относительно безболезненным для создания потоков в ядре.

Основные функции для создания и завершения потоков ядра:

IOThread IOCreateThread(IOThreadFunc function, void *argument);
IOThread IOThreadSelf(void);
void IOExitThread(void);

За исключением IOCreateThread (который немного более сложен), функции Набора I/O являются довольно тонкими обертками вокруг функций потока Маха. Включенные типы являются также очень тонкими абстракциями. IOThread действительно то же как thread_t.

IOCreateThread функция создает новый поток, сразу начинающий выполнять функцию, которую Вы указываете. Это передает отдельный аргумент той функции. Если необходимо передать больше чем один параметр, необходимо динамично выделить структуру данных и передать указатель на ту структуру.

Например, следующий код создает поток ядра и выполняет функцию myfunc в том потоке:

#include <IOKit/IOLib.h>
#include <libkern/libkern.h>
#include <sys/malloc.h>
 
struct mydata {
    int three;
    char *string;
};
 
static void myfunc(void *myarg) {
    struct mydata *md = (struct mydata *)myarg;
    IOLog("Passed %d = %s\n", md->three, md->string);
    IOExitThread();
}
 
void start_threads() {
    IOThread mythread;
    struct mydata *md = (struct mydata *)malloc(sizeof(*md));
    md->three = 3; md->string = (char *)malloc(2 * sizeof(char));
    md->string[0] = '3'; md->string[1] = '\0';
 
    // Start a thread using IOCreateThread
    mythread = IOCreateThread(&myfunc, (void *)md);
}

Одна другая полезная функция thread_terminate. Это может использоваться для уничтожения произвольного потока (кроме, конечно, в настоящее время рабочего потока). Это может быть чрезвычайно опасно если не сделанный правильно. Перед разъединением потока с thread_terminate, необходимо заблокировать поток и отключить любые выдающиеся таймеры против него. Если Вы не деактивируете таймер, то паника ядра произойдет, когда истечет таймер.

С этим в памяти, можно быть в состоянии завершить поток следующим образом:

thread_terminate(getact_thread(thread));

Там распараллельте, имеет тип thread_t. В целом Вас можно только уверить, что можно уничтожить себя, не другие потоки в системе. Функция thread_terminate берет единственный параметр типа thread_act_t (активация потока). Функция getact_thread садится на экспресс потока (thread_shuttle_t) или thread_t и возвращает активацию потока, связанную с ним.

SPL и Друзья

Основанные на BSD и основанные на Махе операционные системы содержат устаревшие функции, разработанные для основной однопроцессорной синхронизации. Они включают функции такой как splhigh, splbio, splx, и другие подобные функции. Так как эти функции не особенно полезны для синхронизации в ситуации SMP, они не особенно полезны как инструменты синхронизации в OS X.

При портировании устаревшего кода от более ранних основанных на Махе или основанных на BSD операционных систем необходимо найти альтернативные средние значения обеспечения синхронизации. Во многих случаях это столь же просто как взятие ядра или сетевой трубы. В частях ядра, использовании spl функции ничего не делают, но не наносят ущерба при содержании трубы (и результаты в панике, если Вы не). В других частях ядра, spl макросы фактически используются. Поскольку spl не может обязательно использоваться в его намеченной цели, это не должно использоваться в целом, если Вы не пишете код это часть ядра, уже использующего его. Необходимо вместо этого использовать альтернативные примитивы синхронизации, такие как описанные в Примитивах Синхронизации.

Ожидайте очереди и ожидайте примитивы

Очередь ожидания API используется экстенсивно планировщиком и близко связывается к планировщику в его реализации. Это также используется экстенсивно в блокировках, семафорах и других примитивах синхронизации. Очередь ожидания API является и мощным и гибким, и в результате является несколько большим. Не весь API экспортируется вне планировщика, и части не полезны вне контекста самих функций очереди ожидания. Этот раздел документы только общедоступный API.

Очередь ожидания API включает следующие функции:

void wait_queue_init(wait_queue_t wq, int policy);
extern wait_queue_t wait_queue_t wait_queue_alloc(int policy);
void wait_queue_free(wait_queue_t wq);
void wait_queue_lock(wait_queue_t wq);
void wait_queue_lock_try(wait_queue_t wq);
void wait_queue_unlock(wait_queue_t wq);
boolean_t wait_queue_member(wait_queue_t wq, wait_queue_sub_t wq_sub);
boolean_t wait_queue_member_locked(wait_queue_t wq, wait_queue_sub_t  wq_sub);
kern_return_t wait_queue_link(wait_queue_t wq, wait_queue_sub_t  wq_sub);
kern_return_t wait_queue_unlink(wait_queue_t wq, wait_queue_sub_t  wq_sub);
kern_return_t wait_queue_unlink_one(wait_queue_t wq,
            wait_queue_sub_t *wq_subp);
void wait_queue_assert_wait(wait_queue_t wq, event_t event,
            int interruptible);
void wait_queue_assert_wait_locked(wait_queue_t wq, event_t event,
            int interruptible, boolean_t unlocked);
kern_return_t wait_queue_wakeup_all(wait_queue_t wq, event_t event,
            int result);
kern_return_t wait_queue_peek_locked(wait_queue_t wq, event_t event,
            thread_t *tp, wait_queue_t *wqp);
void wait_queue_pull_thread_locked(wait_queue_t wq, thread_t thread,
            boolean_t unlock);
thread_t wait_queue_wakeup_identity_locked(wait_queue_t wq, event_t  event,
            int result, boolean_t unlock);
kern_return_t wait_queue_wakeup_one(wait_queue_t wq, event_t event,
            int result);
kern_return_t wait_queue_wakeup_one_locked(wait_queue_t wq, event_t  event,
            int result, boolean_t unlock);
kern_return_t wait_queue_wakeup_thread(wait_queue_t wq, event_t  event,
            thread_t thread, int result);
kern_return_t wait_queue_wakeup_thread_locked(wait_queue_t wq, event_t  event,
            thread_t thread, int result, boolean_t unlock);
kern_return_t wait_queue_remove(thread_t thread);

Большинство функций и их параметры являются прямыми и не представлены подробно. Однако некоторые требуют особого внимания.

Большинство функций берет event_t в качестве параметра. Они могут быть произвольными 32-разрядными значениями, который приводит к потенциалу для конфликтных событий на определенных очередях ожидания. Традиционный способ избежать этой проблемы состоит в том, чтобы использовать адрес объекта данных, так или иначе связанного с рассматриваемым кодом как то 32-разрядное целочисленное значение.

Например, если Вы ожидаете события, указывающего, что новый блок данных был добавлен к кольцевому буферу, и если вызвали головной указатель того кольцевого буфера rb_head, Вы могли бы передать значение &rb_head как идентификатор события. Поскольку ожидают, использование очереди обычно не пересекает границы адресного пространства, это обычно достаточно для предотвращения любых конфликтов идентификатора события.

Заметьте функции, заканчивающиеся в _locked. Эти функции требуют, чтобы Ваш поток содержал блокировку на очереди ожидания, прежде чем их вызовут. Функции, заканчивающиеся в _locked эквивалентны их незаблокированным дубликатам (где применимо) за исключением того, что они не блокируют очередь на записи и могут не разблокировать очередь на выходе (в зависимости от значения unlock). Остаток от этого раздела не дифференцируется между заблокированными и разблокированными функциями.

wait_queue_alloc и wait_queue_init функции берут параметр политики, который может быть одним из следующего:

  • SYNC_POLICY_FIFO— сначала - в, сначала

  • SYNC_POLICY_FIXED_PRIORITY— политика на основе приоритета потока

  • SYNC_POLICY_PREPOST— отслеживайте число пробуждений, где никакой поток не ожидал, и позвольте потокам сразу продолжать выполняться, не ожидая, пока то количество не достигает нуля. Это часто используется при реализации семафоров.

Вы не должны использовать wait_queue_init функционируйте вне планировщика. Поскольку очередь ожидания является непрозрачным объектом вне того контекста, Вы не можете определить надлежащий размер для выделения. Таким образом, потому что размер мог измениться в будущем, необходимо всегда использовать wait_queue_alloc и wait_queue_free если Вы не пишете код в самом планировщике.

Точно так же функции wait_queue_member, wait_queue_member_locked, wait_queue_link, wait_queue_unlink, и wait_queue_unlink_one операции на подчиненных очередях, не экспортирующихся вне планировщика.

Функция wait_queue_member определяет, является ли подчиненная очередь участником очереди.

Функции wait_queue_link и wait_queue_unlink соедините и расцепите данную подчиненную очередь от ее родительской очереди, соответственно.

Функция wait_queue_unlink_one расцепляет первую подчиненную очередь в данном родителе и возвращает его.

Функция wait_queue_assert_wait заставляет вызывающий поток ожидать на очереди ожидания, пока это или не прервано (таймером потока, например) или явно пробуждено другим потоком. interruptible флаг указывает, должна ли эта функция позволить асинхронному событию прерывать ожидание.

Функция wait_queue_wakeup_all будит все потоки, ожидающие на данной очереди определенного события.

Функция wait_queue_peek_locked возвращает первый поток из данной очереди ожидания, ожидающей на данном событии. Это не удаляет поток из очереди, и при этом это не будит поток. Это также возвращает очередь ожидания, где был найден поток. Если поток найден в подчиненной очереди, другие подчиненные очереди разблокированы, как родительская очередь. Только очередь, где поток был найден, остается заблокированной.

Функция wait_queue_pull_thread_locked вытягивает поток от очереди ожидания и дополнительно разблокировал очередь. Это обычно используется с результатом предыдущего вызова к wait_queue_peek_locked.

Функция wait_queue_wakeup_identity_locked будит первый поток, ожидающий данного события на данной очереди ожидания и запускающий его выполнение, но оставляющий поток заблокированным. Это тогда возвращает указатель на поток. Это может использоваться, чтобы разбудить первый поток в очереди и затем изменить несвязанные структуры, на основе которых поток был фактически пробужден прежде, чем позволить потоку выполняться.

Функция wait_queue_wakeup_one будит первый поток, ожидающий данного события на данной очереди ожидания.

Функция wait_queue_wakeup_thread будит данный поток, если и только если он ожидает на указанном событии, и ожидайте очередь (или один из ее подчиненных).

Функция wait_queue_remove будит данный поток вне зависимости от очереди ожидания или события, на котором она ожидает.