6.4.1 Эмуляция интерфейсов мьютекса RTOS

Предыдущая  Содержание  Следующая V*D*V

Прототипами интерфейсов мьютекса в нашей RTOS являются:

 

rtosError_t rtosMutexInit(rtosMutex_t *mutex): инициализация мьютекса для операций блокировки, разблокировки и пробной блокировки.

rtosError_t rtosMutexLock(rtosMutex_t *mutex): захват мьютекса, если он не заблокирован; засыпание, если мьютекс уже заблокирован.

rtosError_t rtosMutexUnlock(rtosMutex_t *mutex): разблокировка мьютекса, захваченного ранее вызовом rtosMutexLock.

rtosError_t rtosMutexTrylock(rtosMutex_t *mutex): захват мьютекса, если он не заблокирован. Возвращает RTOS_AGAIN,  если мьютекс уже заблокирован.

 

Обратите внимание, что все вышеперечисленные интерфейсы возвращают одно из значений enum rtosError_t, находящегося в файле rtosTypes.h. Этот файл RTOS включён в ospl.h.

 

typedef enum {

  RTOS_OK,

  RTOS_AGAIN,

  RTOS_UNSUPPORTED,

    ...

  RTOS_ERROR,

}rtosError_t;

 

Эти функции в качестве аргумента принимают указатель на объект rtosMutex_t. rtosMutex_t эмулируется в файле ospl.h следующим образом:

 

#ifndef __KERNEL__

  typedef pthread_mutex_t rtosMutex_t; <-- определение

                            в пространстве пользователя

#else

  typedef struct semaphore rtosMutex_t; <-- определение

                                            в ядре

#endif

 

В пользовательском пространстве интерфейсы мьютекса RTOS эмулируются c использованием мьютексных операций pthread-ов. В ядре они эмулируются с использованием семафоров ядра. Давайте поговорим о реализации этих интерфейсов в нашем OSPL.

Функция rtosMutexInit эмулируется в пользовательском пространстве с помощью функции pthread_mutex_init. В ядре  используется функция init_MUTEX. init_MUTEX инициализирует семафор значением 1.

 

rtosError_t rtosMutexInit(rtosMutex_t *mutex){

#ifndef __KERNEL__

  pthread_mutex_init(mutex, NULL);

#else

  init_MUTEX(mutex);

#endif

  return RTOS_OK;

}

 

Версия rtosMutexLock для пользовательского пространства использует функцию pthread_mutex_lock. В ядре используется функция down.

 

rtosError_t rtosMutexLock(rtosMutex_t *mutex){

  int err;

#ifndef __KERNEL__

  err = pthread_mutex_lock(mutex);

#else

  down(mutex);

  err = 0;

#endif

  return (err == 0) ? RTOS_OK : RTOS_ERROR;

}

 

down автоматически уменьшает счётчик семафора. Семафор захвачен, если после уменьшения счётчик становится нулевым; если счётчик становится отрицательным, то текущая задача помещается в непрерываемый сон на очереди ожидания семафора.Задача пробуждается только когда владелец семафора освобождает его, вызвав функцию up. Недостатком использования down является её врождённый непрерываемый сон. Вы никак не может прекратить выполнение задачи, которая спит в down. Чтобы полностью контролировать выполнение задачи, вместо неё должна использоваться функция down_interruptible. Функция аналогична down, за исключением того, что возвращает -EINTR, если сон прерван. Таким образом новой реализацией rtosMutexLock является:

 

rtosError_t rtosMutexLock(rtosMutex_t *mutex){

  int err;

#ifndef __KERNEL__

  err = pthread_mutex_lock(mutex);

#else

  err = down_interruptible(mutex);

#endif

  return (err == 0) ? RTOS_OK : RTOS_ERROR;

}

 

Функция rtosMutexUnlock реализована в пользовательском пространстве с помощью функции pthread_mutex_unlock. В ядре используется функция up. up атомарно увеличивает счётчик семафора и пробуждает задачи, спящие (прерываемым или  непрерываемым сном) на очереди ожидания семафора.

 

rtosError_t rtosMutexUnlock(rtosMutex_t *mutex){

  int err;

#ifndef __KERNEL__

  err = pthread_mutex_unlock(mutex);

#else

  up(mutex);

  err = 0;

#endif

  return (err == 0) ? RTOS_OK : RTOS_ERROR;

}

 

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

 

rtosError_t rtosMutexTrylock(rtosMutex_t *mutex){

  int err;

#ifndef __KERNEL__

  err = pthread_mutex_trylock(mutex);

  if (err == 0)

    return RTOS_OK;

  if (errno == EBUSY)

    return RTOS_AGAIN;

  return RTOS_ERROR;

#else

  err = down_trylock(mutex);

  if (err == 0)

    return RTOS_OK;

  return RTOS_AGAIN;

#endif

}

 

Чтобы подвести итог, в Таблице 6.1 перечислены соответствия один-к-одному между интерфейсами мьютекса RTOS и интерфейсами мьютекса Linux.

 

Таблица 6.1 Интерфейсы мьютекса RTOS и Linux

 

RTOS

Linux

User Space

Kernel Space

Инициализация мьютекса

pthread_mutex_init

init_MUTEX

Блокировка мьютекса

pthread_mutex_lock

down_interruptible

Разблокировка мьютекса

pthread_mutex_unlock

up

Пробная блокировка мьютекса

pthread_mutex_trylock

down_trylock

 

Предыдущая  Содержание  Следующая