You are here

Сохранение контекста задачи ОС

Перевод может содержать ошибки. Читайте первоисточник: Saving the RTOS Task Context

Назад: [Как работает FreeRTOS] Вверх: [Как работает FreeRTOS] Вперёд: [Как работает FreeRTOS]

 

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

Сохранение контекста реализовано макросом portSAVE_CONTEXT(), исходный код которого приведён ниже:

/*----------------------------------------------------------------------------*/
#define portSAVE_CONTEXT()           \ (0)
asm volatile (	                     \
  "push  r0                    \n\t" \ (1)
  "in    r0, __SREG__          \n\t" \ (2)
  "cli                         \n\t" \ (3)
  "push  r0                    \n\t" \ (4)
  "push  r1                    \n\t" \ (5)
  "clr   r1                    \n\t" \ (6)
  "push  r2                    \n\t" \ (7)
  "push  r3                    \n\t" \
  "push  r4                    \n\t" \
  "push  r5                    \n\t" \

    :
    :
    :

  "push  r30                   \n\t" \
  "push  r31                   \n\t" \
  "lds   r26, pxCurrentTCB     \n\t" \ (8)
  "lds   r27, pxCurrentTCB + 1 \n\t" \ (9)
  "in    r0, __SP_L__          \n\t" \ (10)
  "st    x+, r0                \n\t" \ (11)
  "in    r0, __SP_H__          \n\t" \ (12)
  "st    x+, r0                \n\t" \ (13)
);

Пояснения к исходном коду:

  • (1) Регистр процессора R0 сохраняется первым, т.к. сразу же будет использован при сохранении регистра состояния SREG, и перед этим нужно сохранить его оригинальное значение.
  • (2) Регистр состояния копируется в R0, чтобы в дальнейшем значение сохранить в стеке (4).
  • (3) Запрещаем прерывания процессора. Если макрос portSAVE_CONTEXT() был только вызван из обработчика прерывания, тогда нет необходимости явно отключать прерывания, т.к. ядро процессора AVR уже сделало это автоматически. А поскольку макрос portSAVE_CONTEXT() используется также вне обработчиков прерываний (когда задача приостанавливает сама себя), прерывания должны быть явно запрещены как можно раньше.
  • (5) Сохраняем регистр R1, т.к. код обработчика прерывания, генерируемый компилятом (GCC), предполагает, что R1 установлен в 0...
  • (6) ...и сразу же устанавливаем значение регистра R1 в 0 (очищаем регистр).
  • Начиная с (7) и до строки перед (8) все остальные регистры сохраняются в стреке в порядке их номеров.
  • (8 и 9) Стек приостановленной задачи теперь содержит копию контекста выполнения. Ядро сохраняет указатель стека задачи, чтобы при возвобновлении задачи контекст можно было извлечь и восстановить.  Для этого в регистровую пару X (r27:r26) загружается адрес, по которому будет сохранён указатель стека.
  • (10 и 11) Сохраняется младший байт указателя стека.
  • (12 и 13) Сохраняется старший байт указателя стека.

Далее: Реализация FreeRTOS - Восстановление контекста

Hobby's category: