### [ На русском ] ↔ [ English ]

- Просмотр информации о процессах
- Управление процессами
- Приостановка, возобновление и завершение
- Приоритеты задач, установка приоритета

## ⇮ПРОСМОТР ИНФОРМАЦИИ О ПРОЦЕССАХ

Как и в других случаях, информация о задачах доступна с помощью команды "show":

Команда | Описание и примеры
--- | ---
show tasks | Выводит список запущенных процессов, их ID, приоритет, имя и состояние:
    esp32#>show ta
    %  # |  Task  ID  |        Name      | Prio |   State
    %----+------------+------------------+------+-----------
    %   1| 0x3fca300c |         ESPShell |   5  | Running
    %   2| 0x3fca7264 |            IDLE0 |   0  | Ready
    %   3| 0x3fca5f64 |              pin |   0  | Ready
    %   4| 0x3fca783c |            IDLE1 |   0  | Ready
    %   5| 0x3fcaace8 |         loopTask |   1  | Waiting
    %   6| 0x3fca85f4 |          Tmr Svc |   1  | Waiting
    %   7| 0x3fca1790 |             ipc1 |  24  | Suspended
    %   8| 0x3fca11f8 |             ipc0 |  24  | Suspended
    %   9| 0x3fca5484 |        esp_timer |  22  | Suspended
    %----+------------+------------------+------+-----------
    % Total: 9 tasks
    esp32#>

## ⇮УПРАВЛЕНИЕ ПРОЦЕССАМИ

Управление процессами реализовано с помощью четырех команд: suspend, resume, priority и kill. Под процессами имеются в виду задачи FreeRTOS: например, основная функция Arduino loop() обрабатывается отдельной задачей FreeRTOS с именем "loop", то есть "loop()" - это процесс (в списке задач он находится под именем "loopTask").

Доступ к задачам и управление ими осуществляется по их TASK_ID (шестнадцатеричное число, например "0x3fca370c") или по имени, за исключением основной задачи loop() Arduino: выполнение основного скетча можно контролировать, опустив параметр TASK_ID в команде. То есть, чтобы приостановить скетч, вместо "suspend 0x12345678" можно использовать команду "suspend" без аргументов.

ВАЖНО: Несколько процессов могут иметь полностью одинаковые имена. Такое происходит, например, когда запускается несколько фоновых команд, скажем, "pin":

      esp32#>pin 2 low delay 100 high delay 100 loop infinite &
      esp32#>pin 4 low delay 200 high delay 200 loop infinite &

В списке процессов будет два процесса с одинаковым именем "pin". В таком случае следует использовать TASK_ID, а не имя. Если же использовать имя задачи, то операция будет производится над первой задачей с таким именем в списке. Порядковый номер задачи в списке постоянно меняется, на него нельзя полагаться.

Хорошо, но где взять эти task id и имена?

Например, можно воспользоваться командой "show tasks":

    esp32#>show tasks
    %  # |  Task  ID  |        Name      | Prio |   State
    %----+------------+------------------+------+-----------
    %   1| 0x3fca783c |            IDLE1 |   0  | Ready
    %   2| 0x3fca7264 |            IDLE0 |   0  | Ready
    %   3| 0x3fca300c |         ESPShell |   0  | Running
    %   4| 0x3fca5f64 |              pin |   0  | Ready
    %   5| 0x3fcaace8 |         loopTask |   1  | Waiting
    %   6| 0x3fca1790 |             ipc1 |  24  | Suspended
    %   7| 0x3fca11f8 |             ipc0 |  24  | Suspended
    %   8| 0x3fca5484 |        esp_timer |  22  | Suspended
    %   9| 0x3fca85f4 |          Tmr Svc |   1  | Waiting
    %----+------------+------------------+------+-----------
    % Total: 9 tasks
    esp32#>

Так же, каждая команда ESPShell, которая запускается как процесс, всегда выводит свой TASK_ID. Допустим, мы запускаем команду "pin 2 delay 1000" в фоновом режиме:

    esp32#>pin 2 delay 1000 &
    % Background task started
    % Copy/paste "kill 0x3ffb91dc" to abort
    esp32#>

Эта простая команда ничего не делает, кроме как ждёт 1000 мс. После запуска она выводит свой task id и команду, которую можно скопировать и выполнить: "kill 0x3ffb91dc".

Другим источником TASK_ID является команда "show counters"

## ⇮ПРИОСТАНОВКА, ВОЗОБНОВЛЕНИЕ И ЗАВЕРШЕНИЕ

Команда | Описание и примеры
--- | ---
suspend | Приостанавливает выполнение скетча: приостанавливает loop() Arduino. Задачи, которые были запущены из loop() и setup(), не приостанавливаются этой командой. Приостановка задачи вместе со всеми её дочерними задачами - запланированная, но пока не реализованная возможность. Комбинация клавиш Ctrl+C является горячей клавишей для команды "suspend"
suspend TASK_ID | suspend TASK_ID Приостанавливает произвольную задачу, если известен её идентификатор. Команда требует один аргумент - идентификатор задачи (в шестнадцатеричном формате)
resume | Возобновляет выполнение скетча
resume TASK_ID | resume TASK_ID Возобновляет произвольную задачу, если известен её идентификатор. Команда требует один аргумент - идентификатор задачи (в шестнадцатеричном формате)

Чтобы остановить задачу ESPShell (ESPShell использует задачи для запуска фоновых команд) или произвольную задачу FreeRTOS, можно воспользоваться командой "kill":

Команда | Описание и примеры
--- | ---
kill TASK_ID | "kill [-TERM | -15 | -KILL | -9] TASK_ID" Останавливает выполнение задачи с TASK_ID. Этот идентификатор либо выводится при запуске фоновой команды, либо может быть произвольным идентификатором FreeRTOS-задачи. Если в конце команды используется символ "&", то ESPShell выполняет такую команду в фоновом режиме, создавая новую задачу:
          esp32#>pin 2 delay 999 &
          % Background task started
          % Copy/paste "kill 0x3fca370c" command to stop execution  ← обратите внимание на TASK_ID
          esp32#>
В простейшем случае, когда используется только один параметр (TASK_ID), команда отправляет уведомление задаче, которую нужно завершить, чтобы она могла завершиться корректно. Команда старается имитировать классическую команду "kill" из Linux и принимает дополнительный параметр - сигнал, который нужно отправить: -9 или -KILL означает принудительное завершение задачи. Уведомление не отправляется, вместо этого задача приостанавливается и удаляется с помощью FreeRTOS API vTaskDelete(). При этом ресурсы, занятые задачей, не освобождаются. Завершение задачи, которая удерживает мьютекс, может привести к зависаниям. Все задачи, создаваемые ESPShell, должны завершаться таким образом - без указания дополнительных параметров. Однако есть примеры команд ESPShell, которые можно завершить только с помощью "kill -9", эти особые случаи описаны в описании команды "pin". Опция -15, -TERM или её отсутствие означает "корректное завершение": задача не удаляется, а получает возможность завершиться самостоятельно и освободить все используемые ресурсы (если таковые имеются). Опция -9 или -KILL приводит к приостановке задачи с её последующим удалением через API FreeRTOS vTaskDelete(). Эта опция эквивалентна команде Linux "kill -9", но в отличие от неё, ESPShell не освобождает ресурсы, которые могли быть выделены задачей.

## ⇮ПРИОРИТЕТЫ ПРОЦЕССОВ, УСТАНОВКА ПРИОРИТЕТА

В ESP32 процессами (задачами) управляет модифицированная FreeRTOS, которая является одним из компонентов ESP-IDF.

Задачи, находящиеся под управлением FreeRTOS, получают управление в соответствии с присвоенными им приоритетами. Приоритет может принимать значение от 0 до 24: чем больше число, тем выше приоритет.

С максимальным приоритетом запускаются системные задачи межпроцессорного взаимодействия — ipc0 и ipc1. Высокий приоритет присвоен компонентам Bluetooth и Wi-Fi. Минимальный приоритет имеют так называемые idle-процессы: IDLE0 и IDLE1.

По умолчанию ESPShell запускается с приоритетом 0, что соответствует уровню системных idle-процессов. Все вспомогательные задачи, создаваемые шеллом, также запускаются с этим приоритетом. Приоритет задач, инициируемых шеллом (например, фоновых команд), наследуется от него.

Приоритет можно изменить с помощью команды priority NUM [TASK_ID]. Если второй параметр (ID задачи) опущен, новое значение устанавливается для самого шелла. Если указан — приоритет будет изменён у соответствующей задачи.

Пример: посмотреть, какой приоритет установлен у шелла, поменять его на 5

    esp32#>sh ta
    %  # |  Task  ID  |        Name      | Prio |   State
    %----+------------+------------------+------+-----------
    %   1| 0x3fca5f64 |              pin |   0  | Ready
    %   2| 0x3fca7264 |            IDLE0 |   0  | Ready
    %   3| 0x3fca300c |         ESPShell |   0  | Running
    %   4| 0x3fca783c |            IDLE1 |   0  | Ready
    %   5| 0x3fcaace8 |         loopTask |   1  | Waiting
    %   6| 0x3fca11f8 |             ipc0 |  24  | Suspended
    %   7| 0x3fca5484 |        esp_timer |  22  | Suspended
    %   8| 0x3fca85f4 |          Tmr Svc |   1  | Waiting
    %   9| 0x3fca1790 |             ipc1 |  24  | Suspended
    %----+------------+------------------+------+-----------
    % Total: 9 tasks
    esp32#>prio 5
    esp32#>sh ta
    %  # |  Task  ID  |        Name      | Prio |   State
    %----+------------+------------------+------+-----------
    %   1| 0x3fca300c |         ESPShell |   5  | Running
    %   2| 0x3fca7264 |            IDLE0 |   0  | Ready
    %   3| 0x3fca783c |            IDLE1 |   0  | Ready
    %   4| 0x3fca5f64 |              pin |   0  | Ready
    %   5| 0x3fcaace8 |         loopTask |   1  | Waiting
    %   6| 0x3fca5484 |        esp_timer |  22  | Suspended
    %   7| 0x3fca85f4 |          Tmr Svc |   1  | Waiting

Примечание о приоритетах задач:
Команда шелла pin 2 low high loop inf генерирует прямоугольный сигнал с частотой 150 кГц при запуске с приоритетом IDLE. Однако при повышении приоритета до 2 частота увеличивается до 560 кГц. Это происходит потому, что команда pin никогда не уступает управление процессору, не позволяя задачам с более низким приоритетом выполняться.