Программирование DSP Использование потоко-безопасных библиотек VisualDSP Wed, November 22 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Использование потоко-безопасных библиотек VisualDSP Печать
Добавил(а) microsin   

Этот документ описывает, как использовать потоко-защищенные библиотеки (thread-safe C/C++ libraries), предоставляемые средой разработки VisualDSP++ 4.5, вместе с различными системами RTOS сторонних разработчиков (не VDK). Эта информация дается в качестве руководства для пользователей, которые хорошо понимают принципы многопоточной разработки и процедуры программирования, используемые в операционных системах RTOS (перевод документации EE-303 [1]).

Примечание: Thread-safe-библиотеки специально разработаны для работы в окружении VDK RTOS. VDK это единственная многопоточная конфигурация подобного рода, официально поддерживаемая средой VisualDSP++ компании Analog Devices.

[Общая информация]

Библиотеки C и C++, поставляемые вместе с VisualDSP++ 4.5 доступны в нескольких вариантах, некоторые из которых считаются безопасными с точки зрения выполнения в многопоточной среде (multithreaded environment). Эти thread-safe версии библиотек были разработаны как ответ на требования VDK kernel, и они не были предназначены для использования вместе с другими RTOS. Путем замены функций VDK, вызываемых из библиотек C/C++ их эквивалентами из альтернативных RTOS, добавлением соответствующей поддержки инициализации объектов и модификацией файла настройки линкера (Linker Description File, *.LDF) можно интегрировать эти библиотеки в другое рабочее окружение.

Подразумевается, что пользователи, которые хотят использовать альтернативную RTOS, будут использовать код инициализации, предоставленный разработчиком RTOS, отвечающий за инициализацию кучи и стека, файлового ввода/вывода (file I/O) и других требуемых компонентов. Это отменяет поведение кода инициализации, по умолчанию предоставляемое средой VisualDSP++. Для подключения этих новых объектов требуется правильно настроенный файл .LDF [3], предоставленные для соответствующей RTOS.

Когда используется многопоточная библиотека C (multithreaded C run-time support library), приложение должно быть ликовано вместе с соответствующей многопоточной библиотекой C++ (multithreaded C++ run-time support library). Библиотека C требует использования класса мьютекса, определенного в библиотеке C++.

[Блокировка и разблокировка критических секций кода в библиотеках C/C++]

Библиотеки C и C++ (C/C++ runtime support libraries), предоставляемые вместе с VisualDSP++ 4.5, используют некоторые функции VDK для организации последовательного доступа к критическим секциям кода (что такое необслуживаемые и критические регионы кода, см. Q002 [2]).

Эта функция вызывается всякий раз при входе в критическую область кода (critical section). Функция гарантирует, что планировщик не прервет контекст выполнения текущего потока до выхода из критической области. Вызовы PushUnscheduledRegion могут быть вложены друг в друга, если обеспечивается парность вызовов PushUnscheduledRegion и PopUnscheduledRegion. Для получения подробностей см. руководство VisualDSP++ Kernel (VDK) User’s Guide.

Это функция, парная для функции PushUnscheduledRegion. Она вызывается при выходе из критической области кода. Вызовы PopUnscheduledRegion могут быть вложенными, если обеспечивается парность вызовов PushUnscheduledRegion и PopUnscheduledRegion. Для получения подробностей см. руководство VisualDSP++ Kernel (VDK) User’s Guide.

Эта функция создает мьютекс размера size. В вызовах из runtime-библиотек thread-safe размер мьютекса может быть 5*sizeof(int). В thread-safe библиотеках память, на которую указывает mutex, выделяется вызовом malloc() перед тем, как этот указатель передается в функцию RMutexInit.

Эта функция уничтожает мьютекс, связанный с указателем mutex. Память, выделенная для этого мьютекса, не освобождается вызовом этой функции, и она должна быть освобождена независимо.

Эта функция захватывает мьютекс, на который указывает параметр mutex.

Эта функция освобождает мьютекс, на который указывает параметр mutex.

Рекомендуется заменить эти функции, создав функции с такими же именами, которые будут выполнять те же самые действия в альтернативных RTOS.

Имейте в виду, что мьютекс VDK реализован как рекурсивный, т. е. вложенные захваты мьютекса одним и тем же потоком разрешены и безопасны. Реализация мьютекса отслеживает как захваты текущего владельца мьютекса (если он есть), так и количество вложенных захватов мьютекса его владельцем (владелец это поток, который вызвал RMutexAcquire). Мьютекс не освобождается, пока его счетчик не дойдет до нуля.

Механизм блокировки VDK, который вызывается из библиотек C и C++, относится только к действиям планировщика, но не к прерываниям (блокировка не запрещает прерывания). На совести разработчика остается правильное использование этих функций.

Примечание: в VDK среды VisualDSP++ 5.0 предусмотрены механизмы так называемых необслуживаемых регионов кода и критических регионов кода. В критических регионах прерывания запрещены, а в необслуживаемых запрещено только лишь переключение контекста планировщиком, подробнее см. Q002 [2].

Библиотеки C и C++ разработанные только как thread-safe, без обеспечения реентерабельности. Поэтому обработчики прерываний (interrupt service routines, ISR) не должны вызывать библиотечные функции C или C++, которые в случае использования в контексте ISR могут работать непредсказуемо. Дополнительную информацию по вызову библиотечных функций из ISR можно найти в руководстве "VisualDSP++ C/C++ Compiler and Library Manual".

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

[Где хранится информация потоков (Thread-Local Storage)]

Библиотека C поддерживает локальное хранилище данных потоков с целью сохранения данных между вызовами функций для следующих наборов данных:

errno. Значение errno специфично для потока. Каждый поток использует локальное хранилище для сохранения значения errno.

strtok(). Функция strtok() использует локальное хранилище для сохранения внутренних указателей между вызовами функции.

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

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

Подпрограммы, описанные выше, полагаются на работу трех функций в VDK. Аналогичные функции доступны в большинстве RTOS.

Эта функция выделяет новый слот хранилища потока, если он не был уже назначен. У функции VDK есть несколько возвращаемых значений. Обратитесь к соответствующей документации по VDK API "VisualDSP++ Kernel (VDK) User’s Guide", чтобы альтернативные функции могли эмулировать поведение AllocateThreadSlotsEx.

Эта функция вернет указатель на локальные сохраненные данные потока. Обратитесь к соответствующей документации по VDK API "VisualDSP++ Kernel (VDK) User’s Guide" для получения информации о функции GetThreadSlotValue.

Эта функция сохраняет указанные данные в области слота потока. Обратитесь к соответствующей документации по VDK API "VisualDSP++ Kernel (VDK) User’s Guide" для получения информации о функции SetThreadSlotValue.

[Модификация LDF]

Файл настроек линкера [3] (Linker Description File, файл с расширением *.LDF), используемый проектом VDK, отличается от стандартного файла .LDF потому что он по умолчанию задает линковку программы пользователя вместе со специальной версией библиотек, обеспечивающей безопасную работу потоков (thread-safe version библиотек C/C++).

Файл .LDF по умолчанию для обычного проекта (не VDK) не содержит поддержку для многопоточных библиотек. Пользователи, которые хотят использовать альтернативную RTOS, должны сделать копию стандартного файла .LDF и изменить его так, чтобы он обеспечивал линковку корректных версий библиотек.

Многопоточные библиотеки для процессоров Blackfin® и SHARC® содержат расширение mt (сокращение от multi-thread) в имени библиотеки. Например, C-библиотека ADSP-BF532 имеет имя libc532mt.dlb, а C-библиотека ADSP-21060 называется libcmt.dlb. Многопоточные библиотеки для процессоров TigerSHARC® содержат расширение _mt. Например, C-библиотека ADSP-TS201 называется libc_TS201_mt.dlb.

[Инициализация библиотек C и C++]

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

Start-Up Code. Код запуска (start-up) в файле VisualDSP\Blackfin\lib\src\libc\basiccrt.s поддерживает несколько опций конфигурации. Инсталляция Blackfin включает множество предварительно сконфигурированных комбинаций. Файл .LDF по умолчанию выбирает файл crt*.doj для линковки, основываясь на определениях пользователя и опций компилятора ccblkfn.

FIOCRT. Макрос FIOCRT вычисляется как true, когда мы внутри программы хотим использовать файловый ввод/вывод (file I/O). Разрешение этого определения макроса гарантирует, что подпрограмма _init_devtab будет вызвана для инициализации Вашего метода ввода/вывода.

CPLUSCRT. Должна быть вызвана подпрограмма C++ ___ctorloop. Эта подпрограмма гарантирует, что объекты C++ корректно создаются и уничтожаются. Это также инициализирует фоновые процессы сбора мусора. Подобным образом должна быть также декларирована переменная ___ctor_table в нижней части файла по умолчанию basiccrt.s.

Инициализация FP/SP. Код инициализации должен гарантировать, что регистры указателей стеков FP и SP установлены в правильные значения.

Start-Up Code. Код запуска находится в одном из следующих файлов, в зависимости от елевой архитектуры используемого процессора:

VisualDSP\21k\lib\src\crt_src\020_hdr.asm
VisualDSP\21k\lib\src\crt_src\06x_hdr.asm
VisualDSP\211xx\lib\src\crt_src\16x_hdr.asm
VisualDSP\212xx\lib\src\crt_src\26x_hdr.asm
VisualDSP\213xx\lib\src\crt_src\36x_hdr.asm

Инсталляция SHARC включает множество предварительно подготовленных конфигураций. Когда используется файл .LDF по умолчанию, файл .LDF выбирает для линковки файл *hdr*.doj, основываясь на определениях пользователя и опций компилятора cc21k.

По умолчанию в релиз включается несколько вариантов предварительно собранного кода start-up. Используется соглашение, что имена файлов, предварительно подготовленных модулей start-up, которые поддерживают C++, содержат в составе имени cpp, и thread-safe версии содержат в составе имени _mt.

Определение макроса __cplusplus. Подпрограмма _lib_call_ctors будет подключена, когда определен этот макрос. Эта подпрограмма гарантирует, что объекты C++ будут корректно создаваться и уничтожаться. Эта подпрограмма будет вызываться, когда существует определение __cplusplus при ассемблировании файла *hdr*.asm. Также должна быть декларирована переменная ___ctors; эта переменная должна быть определена в файле .LDF, и она должна указывать на начало секции seg_ctdm.

Start-Up Code. Код запуска start-up в файле исходного кода на ассемблере находится в файле TS\lib\src\crt_src\ts_hdr.asm (путь относительно каталога установки VisualDSP). Инсталляция TigerSHARC включает множество предварительно подготовленных конфигураций. Когда используется файл .LDF по умолчанию, этот файл .LDF выбирает для линковки файл ts_hdr*.doj на основе определений пользователя и опций компилятора ccts.

По умолчанию в релиз включено несколько вариантов предварительно подготовленного кода start-up. По соглашению имена файлов модулей start-up, которые поддерживают C++, содержат в своем имени cpp, а модули с поддержкой thread-safe содержат в имени _mt, и файлы байтового режима адресации start-up содержат в своем имени _ba.

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

Определение макроса _CPLUSPLUS. Подпрограмма C++ ___ctorloop должна быть вызвана, чтобы гарантировать корректное создание и уничтожение объектов C++. Эта подпрограмма вызывается, когда существует определение _CPLUSPLUS при ассемблировании ts_hdr.asm. Эта подпрограмма будет также инициализировать кучу и библиотеку I/O, что должно быть сделано перед их использованием. Подобным образом также должна быть определена переменная ___ctor_table в нижней части файла ts_hdr.asm по умолчанию.

vdkMainMarker. C-переменная vdkMainMarker декларируется в VDK, чтобы оповестить библиотеки run-time о том, что приложение входит в состояние многопоточности. Переменная vdkMainMarker декларируется следующим образом:

int vdkMainMarker = 0;

Эта переменная устанавливается в значение 1 сразу перед тем, как программа вызовет поток загрузки с самым высоким приоритетом (так называемый boot thread, который запускается автоматически). Пока эта переменная установлена в 1, не будут вызываться функции из библиотек run-time, блокирующие VDK. Это реализовано для того, чтобы избежать вызова специфичных для потока функций из не потоковых функций.

Для использования любой RTOS, отличной от VDK, эта переменная должна быть декларирована с начальным нулевым значением, и установлена в 1 непосредственно перед тем, как программа запустит пользовательский boot thread. Это относится к процессорам Blackfin, SHARC и TigerSHARC.

[Ссылки]

1. EE-303 Using VisualDSP++® Thread-Safe Libraries with a Third-Party RTOS site:analog.com.
2. VDK FAQ.
3. Linker Description File.

 

Добавить комментарий


Защитный код
Обновить

Top of Page