На первый взгляд идея рабочая, хотя не уверен, что доберусь до добавления новых элементов в польковательском интерфейсе скоро. Но в качестве минимальной реализации, в конфигурационный файл (`logstreams.yaml`) можно добавить опцию для каждого logstream, типа `persistent_connection: true`, и nerdlog тогда будет поддерживать соединения для этих логстримов постоянно открытыми.
Но этот файл нужно вручную править. Если делать автоматическое запоминание состояния при рестарте, то тут уже и без новых элементов в интерфейсе не обойтись, так что это не сейчас. Но в целом, согласен, что может быть полезно, спасибо за feature request.
Нет ли у вас желания сделать обертку для поддержки и хранения соединений к серверам в сетке?В небольших сетках ограниченное количество серверов и удобно было бы не переподключаться каждый раз.
Можете пояснить, в каком виде представляете эту обертку?
Если я правильно понял идею, то: если не хочется закрывать соединения, просто не закрываете Nerdlog, и все. Т.к. Nerdlog - терминальное приложение, оно будет работать с любым терминальным мультиплексором (типа tmux или screen); так что можно держать несколько открытых nerdlog-ов, если хочется. Я не знаю, какие подобные мультиплексоры есть в Windows, но наверняка есть что-то подобное.
Ну и, конечно, можно просто держать открытым и один экземпляр nerdlog, подключенный сразу ко всем серверам, которые вам часто нужны.
MacOS не серверная, но прочитать логи из localhost все равно удобно. Когда я этот проект только что опубликовал, несколько человек сразу сказали, что хотят поддержку localhost без ssh.
С gawk - да, есть такое, хорошо бы добавить поддержку POSIX awk. Но sqlite тут не заменит gawk (т.к. в индекс-файле, о котором идет речь, нет данных из логов - там только таймстампы и соответствующие номера строк и смещения).
Если же вы имели в виду вкачивать все данные из логов в sqlite, то это уж точно перебор для Nerdlog. И место на диске двойное будет занимать (существенно, если размер файл логов измеряется в гигабайтах, как было в нашем оригинальном случае). И для поддержки journalctl пришлось бы тогда все данные оттуда вычитывать сначала, а journalctl медленный, так что это первоначальная инициализация этой базы данных займет кучу времен.
Самая фишка этого проекта в том, чтобы не усложнять больше необходимого, и использовать простые текстовые файлы как "базу данных".
В общем, можно ли так сделать - можно. Но вот стоит ли - я не думаю.
Поздравляю вы почти изборели либо «шитые файлы» - текстовые файлы когда первый столбец содержит длину строки - тогда не приходится просматривать все символы в поисках перевода строки.
Либо недоизобрели базу данных.
Спасибо конечно, но сразу знать абсолютное смещение в файле все равно ведь быстрее, чем пропускать строку за строкой, даже с "шитими файлами" (Кстати, не слышал такого термина раньше, и не гуглится ничего по теме. Но из вашего описания понял, о чем речь)
В вашем первом примере вызов
Cat filename | awk … можно упростить. Выкинуть cat. Awk с флагом -f позволяет читать сразу из файла.
Вы правы, в этом простом примере можно (и даже без флага -f можно - этот флаг нужен только если мы хотим читать сам awk-скрипт из файла). В реальности в Nerdlog так не получится, т.к. ему нужно будет отсечь ненужные части логов с помощью tail и head и уже результат обработать в awk, но да, в этом примере можно. Поправлю.
Если вы обрабатываете файл - создаете индекс по датам, то почему бы не сохранить контент в SQLite?
Потому, что тогда sqlite должен быть установлен на всех хостах, с которых мы хотим читать логи. Цель была - использовать только GNU утилиты, предустановленные почти везде, чтобы Nerdlog работал из коробки.
Хмм, я не завсегдатай на Хабре, и, похоже, неправильно понял предназначение этого хаба: был почему-то уверен, что он для любых небольших утилит и т.д., но сейчас вижу, что это про конкретный фреймворк. Извиняюсь! Нужно было осмотреться получше.
Убрал его из статьи, спасибо, что указали!
Пока что просто в open source, значит. Если считаете, что статья хорошо подойдет в какие-то другие хабы, буду рад совету. Я еще думал про DevOps (т.к. знаю пару devops инженеров, использующих Nerdlog), но т.к. статья скорее про детали реализации, то сомневался про этот хаб, и пока не стал туда добавлять.
А, ну тогда это уже указано в доках (выделение мое):
Likewise, if the host becomes unresponsive for whatever reason, we can't get logs from it either.
И следующий параграф там также упоминает, что это можно решить синхронизацией логов на отдельный хост; rsyslog это умеет, насколько мне известно (но сам я не заморачивался. KISS и все такое).
Вы правы, но это следствие того же ограничения. На Github в этом пункте о дополнительной нагрузке на сервер также указано, что если сервер вообще не отзывается по любой причине, то и логи посмотреть не получится. Но наверное вы правы, что стоит упомянуть и про сценарий со вломом в этом же пункте (если взломщики были настолько аккуратны, что стерли свои следы из логов).
Если Trezor также используется и по своему самому популярному предназначению (cryptocurrency hardware wallet), то использовать его еще и как аутентификатор уже не так неудобно
Для меня лично, лучше не самый удобный форм-фактор с бэкапом, чем удобный без бэкапа. Пока что я вообще продолжаю u2f-zero пользоваться, но Trezor интересен т.к. предлагает бэкап из коробки.
Похоже, ваша ссылка работает только с yubi ключами, мои google titan ключи не прошли.
Работает с моими u2f-zero. А что конкретно означает «не прошли»?
По поводу проверки с отзывом и перерегистрацией — да, это сработает, но нужны доп шаги. Если мы говорим о сколь-нибудь серьезной стратегии бекапов, то обязательно предусматриваем регулярную проверку. А это противоречит концепции замуровывания в стену.
Вообще говоря, что именно делать с бэкап-токеном — каждый решает сам, со всеми вытекающими; и эта свобода (и, конечно, ответственность) мне нравится. Если есть желание периодически его перепроверять — можно держать его в сейфе, и это все равно (для меня) было бы значительно лучше, чем независимый токен, т.к. я совсем не хочу добавлять бэкап-токен вручную на каждый сервис.
Плюс к этому, в соседней ветке обсуждаем Trezor — если с ним все сработает, то я рассматриваю «замуровать в стену» не только девайс, но еще и seed phrase набитой на металлической пластине. Таким образом, даже если с девайсом по прошествии лет что-то случится, то все равно будет возможность его восстановить из seed phrase (можно было бы этим seed и ограничиться, но никто не знает, что станет с этой компанией Trezor впоследствии и насколько легко можно будет купить новый токен, так что предпочитаю просто иметь готовый бэкап-токен)
Ух ты! Я знал, что Trezor поддерживает U2F с некоторых пор, но ранее не нашел, что counter тоже можно устанавливать. Видимо, я плохо искал: действительно, есть такое, судя по wiki для trezorctl.
Что ж, спасибо за полезный комментарий! Похоже, заказываю Trezor.
Я согласен, что иметь возможность самостоятельно запрограммировать device_secretи константу для увеличения counter в U2F-токен было бы очень здорово, и это именно тот уровень поддержки от производителей токенов, которого я бы хотел видеть, рано или поздно. Опять же, не нужно будет доверяться производителям в том, что они не хранят у себя ключей.
Такая возможность не решает вашей задачи иметь несколько ключей по подзадачам, но устраняет источник риска в виде электронного устройства.
(Только для хранения ключа (device_secret) вместо ламинированного листка бумаги я бы использовал что-то вроде этого + punch kit)
Это разве что-то новое? Такой подход считался лучшим решением для бэкапа в 2018, и считается до сих пор; хотя это и не принято считать проблемой. В статье я аргументирую, почему мне это не нравится, и предлагаю лучшее решение.
2. Все ваши андроиды и виндоусы теперь FIDO2 аутентификатор
Дело предпочтений, но я лично стараюсь воздержаться от использования телефонов и ноутбуков в качестве аутентификаторов; маленький USB-токен, который почти всегда при мне, вместе с другими ключами, и достается гораздо реже, чем телефон или ноутбук — более надежное решение.
По поводу остального — не вижу, как это делает материал в статье менее актуальным. И делегированное восстановление, и WebAuthn backup extension требуют поддержки со стороны Relying Party (RP), то есть сервисов, и в итоге сервисы могут поддерживать такое восстановление, а могут и не поддерживать. То есть, мы будем просто иметь больше неуниверсальных методов восстановления.
В статье же предлагается решение, совершенно независимое от сервисов; которое можно применить уже сегодня, и оно сразу оказывается рабочим для абсолютно всех сервисов, поддерживающих U2F.
Самое первое, что нужно сделать — это протестировать оба токена на demo.yubico.com/webauthn-technical: регистрируем основной токен, потом аутентифицируемся с ним же, проверяем, что signatureCounter низкий (видно, если раскрыть «Technical Details -> Response from the Relying Party»), потом аутентифицируемся с бэкап токеном, убеждаемся, что это работает, и что signatureCounter высокий.
После этого можно удостовериться, что все работает и на настоящих сервисах. Берем какой-нибудь сервис (например, Google), добавляем туда основной токен, выходим, аутентифицируемся с основным токеном, выходим, аутентифицируемся с бэкап-токеном (убеждаемся, что это работает), выходим, пытаемся аутентифицироваться с основным токеном (убеждаемся, что это НЕ работает, т.к. бэкап уже засветился), после чего аутентифицируемся с бэкап-токеном, отзываем токен, и добавляем его заново (основной токен, конечно).
Я провел такую процедуру на нескольких сервисах, и для меня это было достаточным доказательством работоспособности бэкапа в принципе, так что я мог со спокойной душой его закапывать / замуровывать итд. Единственное, что не гарантируется — это аннулирование основного токена после использования бэкапа (т.к. сервис может игнорировать counter), но сам бэкап будет работать на всех сервисах.
По-моему, в контроллерах, на которых вообще имеет смысл использовать вытесняющую РТОС, все в порядке с адресной арифметикой. Например, на том же PIC32 (т.е. MIPS), имея в регистре адрес, загрузить слово по данному адресу с 16-битным знаковым смещением — одна инструкция (и один такт). На Cortex-M — тоже. Это в простых 8-битниках, конечно, все плохо с подобными вещами, но там и вообще вытесняющей РТОС делать нечего.
Что именно вы предлагаете, я так и не понял. Насколько понял — должен быть какой-то отдельный буфер, который будет заранее рассчитан на определенное количество задач. Уже это мне не нравится — гораздо лучше иметь просто связанный список, в который можно динамически добавлять/убирать сколько угодно дескрипторов.
Для того, чтобы обществу (и в первую очередь, мне самому) было проще переносить на TNeo существующие TNKernel-овские проекты, существует режим совместимости: выключаем рекурсивные мютексы, включаем совместимость с евентами. После этого, чтобы перенести проект с TNKernel на TNeo, потребуются тривиальные изменения в приложении, если вообще потребуются. Обеспечить полную совместимость не удастся как минимум потому, что порты TNKernel под разные платформы уже несовместимы между собой: по-разному выделяется память под системные задачи, по-разному система стартует, по-разному задачи создаются. Все отличия API перечислены на страничке Differences from TNKernel API.
Более того, в «официальном» TNKernel под Cortex есть архитектурные особенности, сохранять совместимость с которыми нет никакого желания:
Там есть Timer Task, который не привносит ничего, кроме оверхеда по производительности и памяти. Подробнее тут, тут.
Память для системных вещей (стек для Idle task, Timer task) выделяется статически на этапе компиляции ядра, т.е. нет возможности собрать TNKernel как отдельную библиотеку и просто подключать ее к приложению: надо обязательно собирать TNKernel в составе приложения
Поведение макроса MAKE_ALIG не соответствует даже официальной документации. Подробности тут
RTOS для PIC32, пожалуй, поменьше, чем для Cortex, но хватает. API TNKernel не то чтобы уж необычный, но, тем не менее, перенести проект с TNKernel на TNeo — задача тривиальная, в то время как перенести с TNKernel на FreeRTOS — посложнее. Но ничего невозможного, конечно, нет.
Ну и насчет полезности обществу — простите, если, написав TNeo, я не был достаточно полезным для вас. Я, кстати, думал про блог «я пиарюсь», но решил все-таки написать сюда, т.к. статья, как мне кажется, содержит достаточное количество информации, которая может быть интересна даже тем, кому ни с TNeo, ни с FreeRTOS работать в жизни не придется.
TNeo сохраняет только «callee-saved» регистры, т.е. те, которые должна сохранять вызываемая функция, если эти регистры ей нужны
Сорри, конечно, имелось в виду, наоборот: сохраняются только «caller-saved» регистры, т.е. те, которые должна сохранять вызывающая функция. А о «callee-saved» регистрах как раз позаботится сам ISR.
посмотрел по вашим таймерам. вот вопрос — зачем вообще модифицировать что-то в списке таймеров каждый тик???
делается так.
на системном тике сидит isr который просто инкрементит счетчик системных тиков. при старте он равен 0.
есть общий сортированный по времени срабатывания двусвязный список таймеров.
в начале он пуст.
при запуске таймера высчитывается его время срабатывания = текущее значение счетчика тиков+интервал срабатывания заданный таймеру. то есть вы храните не сам интервал(который декрементите там) а сразу значение счетчике систиков когда сработать(вам больше никакие декременты не нужны).
обьект с посчитанным временем срабатывания заносится в сортированный список. те кто раньше — те в голове.
isr тамера не просто икрементит счетчик тиков, но после этого смотрит — не больше или равен текущий счетчик, тому значению, при котором должен сработать первый в списке(самый ранний таймер). если текущий счетчик больше — первый таймер извлекается и запускается его хук(или что там у вас). если текущий счетчик меньше времени у первого таймера, то ни один таймер еще не созрел. ибо далее в списке — более поздние.
псевдокод иср
void timerISR(){
++__SysCLocks; //это типа системное время в тиках
while(!__TImers.empty() && (__TImers.first()._clocks<__SysClocks)){ //есть созревший таймер
TImer *lt = __Timers.removeFirst(); //
lt->timerAction();
//тут зависит от реализации как реализуется периодичский таймер.
//сам ли он себя обратно вставляет в список таймеров, или это делает данная функция
//а этом псевдокоде таймер однократный
//заметим, что посольку тут while - будут в цикле извлекаьтся все таймеры что созрели к данному тику.
}
}
на самом деле если таймеров разумное количесвто — не тыщщи, таймерная иср только проверит первый в списке таймер на готовность и выйдет.
к чему огород со специальными списками — непонятно.
остается только в момент старта таймера его поставить в нужное место в списке таймеров(сортировка по времени срабатывания в тиках ).
псевдокод startTimer(Timer* ft, int fticks){
ft->_clocks=__SysClocks+fticks; //вычисляем таймеру абс.время его сраатывания в тиках
Timers.addSorted(ft);
}
для оптимизации можно организовать несколько списков таймеров. например для которых квант времени 1 мс, 8 мс, 64 мс… если есть опасение что таймеров будет много… но в релаьном устройстве их, активных ну не более 10. в моей практике всегда одного списка хватало в силу небольшого количества запущенных таймеров.
Ваши доводы насчет таймеров звучат разумно, спасибо. И если включен динамический тик, используется именно такая реализация (потому что там уже и нет периодических тиков, чтобы в них что-то декрементить).
Через год, я уже не очень хорошо помню, почему решил сделать статические таймеры именно так. Возможно, я был просто под впечатлением от реализации в Linux, и хотел сделать похожим образом. Может, переделаю в будущем.
Прежде всего, скажу следующее: существует два подхода к обработке прерываний в РТОС: «Unified» и «Segmented». (не знаю, есть ли устоявшиеся русские термины, так что пишу их на английском). Вот тут есть отличная статья про это: RTOS Interrupt Architectures.
Подход, о котором вы говорите, как о «правильном» (в противоположность моему, «наивному») — это как раз Segmented aproach, когда обработка прерываний разделена на два этапа. В ядре Linux эти два этапа называют top half и bottom half. Тогда, действительно, можно сделать так, что РТОС никогда не запрещает прерывания (как, например, AVIX-RT или Q-kernel).
Но написание приложения под эти два разных типа РТОС существенно отличается (под «Segmented» писать сложнее, подробности в статье по ссылке выше), и, поскольку мне нужна РТОС, максимально совместимая с TNKernel, то этот вариант я не особо рассматривал.
Я не сомневаюсь, что существуют приложения жесткого realtime, где запрещение прерываний недопустимо. В таких проектах, конечно, нужно использовать что-то вроде AVIX-RT. Но мне, честно говоря, несколько десятков тактов под запрещенными прерываниями никогда не мешали, и таких приложений, по-моему, большинство. Плюс к этому, «Segmented» добавляет оверхед к переключению задач. Процитирую заключение из статьи:
While both Segmented and Unified Interrupt Architecture RTOSes enable deterministic real-time management of an embedded system, there are significant differences between them with regard to the efficiency and simplicity of the resulting system. Segmented RTOSes can accurately claim that they never disable interrupts within system services. However, in order to achieve this, they instead must delay application threads, introducing a possibly worse consequence. The segmented approach also adds measurable overhead to the context switch process, and complicates application development. In the end, a unified interrupt architecture RTOS demonstrates clear advantages for use in real-time embedded systems development.
Можно было бы и закончить, но на некоторые вещи отвечу отдельно:
ну например зачем спасать контекст треда если обрабатывается прерывание? если вы хотите переключить треды в результате обработки этого прерывания, это надо сделать позже.
При обработке прерывания, TNeo сохраняет только «callee-saved» регистры, т.е. те, которые должна сохранять вызываемая функция, если эти регистры ей нужны. Если не сохранить их при обработке прерывания, то данные в них будут потеряны. На MIPS TNeo сохраняет их самостоятельно, а, например, Cortex-M делает все за меня, там ядро вообще ничего не делает при обработке прерывания.
треды должны быть изолированы и нельзя чтобы один тред останавливал другой. это в большинстве случаев сделать корректно нельзя. все что может сделать один тред по отношению к другому — запустить тред, послать сообщение в очередь. все. чтобы тред остановить надо посылать ему в очередь сообщение об остановке. поскольку корректно извне тред не остановишь в общем случае.
Тут я с вами соглашусь, и даже вот дам вам ссылку на мой собственный пост на форуме Microchip, где я выражаю ту же идею. Но, первое: как мне там ответил товарищ andersm, эта функциональность довольно стандартна. И второе: мне эта функциональность не мешает, хоть я ее никогда и не использую, так что, чтобы не ломать без надобности совместимость с TNKernel, эти сервисы были оставлены.
надо изолировать треды и прерывания вообще. треды ничего не могут знать про прерывания, а прерывания не могут вызывать тредовые функции. обработчики прерываний лишь берут данные(или не берут ничего) по внешнему событию, и кладут их в очереди, кольцевые буферы, и сигналят неким способом о событии в “мир тредов”. такая штука надывается каналом(обычно кольцевой буфер)
таймеры у вас какие-от странные — там просто сортированная очередь обьектов(двусвязный список) — ближе к голове — наиболее ранний по срабатыванию… а у вас там какой-то наворот, даже не стал разбираться.
Ну то, что вы не стали разбираться и написали об этом, по-моему, вам чести не делает. А реализация таймеров, тем временем, описана даже в статье выше: основная идея позаимствована из ядра Linux, и она более эффективна, чем «просто сортированная очередь».
таймеры надо делать — жесткие и мягкие. жесткие могут работать прямо из контекста таймерного прерывания, а мягкие — запускаются текущим тредом, например при ближайшем переключении тредов. жесткие для жесткого рантайма, мягкие — для каких-то не сильно рантаймовых действия, например светодиодом помигать и так далее.
В TNeo есть жесткие таймеры. А мягких (пока) нет, т.к. лишняя задача в контексте вытесняющей ОС — это, как минимум, два переключения контекста каждый раз, и еще, как минимум, несколько сотен байт для ее стека. RAM в моих проектах — очень дорогой ресурс. Может, в будущем добавлю опционально, но пока мне ни разу не было нужно. Если нужно по таймеру разбудить какую-нибудь задачу, то можно из «жесткого» таймерного коллбэка семафором посигналить, или сообщение в очередь отправить.
обработку прерываний можно разбить на два этапа — isr и dsr…
Насчет этого ответил в самом начале комментария.
критические секции лучше не давать юзеру, любой слип или ожидание в них заблокируют систему. синхронизация делается мьютексом.
После прочтения этого, стало ясно, что мы с вами, возможно, совсем о разных классах систем говорим. Смартфон на Андроиде — это ведь эмбеддинг, и тупой экранчик в заряднике, на камне с 1 кБ RAM — тоже эмбеддинг.
Что значит «лучше не давать юзеру»? В эмбеддинге, РТОС и код приложения очень часто выполняется с одинаковым приоритетом — приоритетом ядра. Так что нет никакой защиты памяти, ничего такого. Это не тот класс систем. Можно, конечно, и на тостер Linux ставить, но это слишком дорого. Так что тут юзер имеет все возможности выстрелить в ногу, и никто ему не поможет.
Синхронизация делается мютексом — отлично. Только не всегда разумно: если нам нужно произвести очень короткое действие (пусть, например, банально поработать с GPIO), то мютекс — это просто колоссальный оверхед, в десятки раз превышающий длительность полезной работы. Мютексом можно ограничивать только сравнительно длительные операции (работа с внешней флешкой, например).
как вы взаимную блокировку там обнаруживаете — непонятно, она может глубоко косвенной, через цепь тредов, когда они по кольцу захватили мьютексы и не отдают.
Именно так, через цепь тредов и проверяется, что непонятного. Да, это занимает время, и именно поэтому я это использую только в отладочной сборке. Осознание того, что у меня там лишние пару десятков тактов будут потрачены на это, меня не пугает — скорости хватает. Будет не хватать — выключу эту опцию в сборке.
все опреации дложны быть с таймаутом, потому дедлоки там в принципе невозможны… дедлоки это у студентов в учебниках.
«дедлоки это у студентов в учебниках» — да уж, рубанули с плеча. Дедлок возникает, если блокировать несколько ресурсов в разной последовательности. В условиях ограниченных ресурсов микроконтроллеров, часто бывает более разумно просто спроектировать систему так, чтобы задачи там блокировали ресурсы только в одной и той же последовательности, вместо того, чтобы обрабатывать ситуацию, когда мы не можем захватить очередной мютекс, поэтому нужно освобождать захваченный в данный момент, и т.д.
Если это правило нарушается, то может возникнуть дедлок, и ядро мне об этом тут же скажет. На сегодняшний день, эта возможность помогла мне ровно один раз (помогла быстро найти ошибку) — что ж, уже неплохо. Если почувствуете необходимость ответить — пишите на почту (у меня на сайте есть адрес), я скопирую сюда.
На первый взгляд идея рабочая, хотя не уверен, что доберусь до добавления новых элементов в польковательском интерфейсе скоро. Но в качестве минимальной реализации, в конфигурационный файл (`logstreams.yaml`) можно добавить опцию для каждого logstream, типа `persistent_connection: true`, и nerdlog тогда будет поддерживать соединения для этих логстримов постоянно открытыми.
Но этот файл нужно вручную править. Если делать автоматическое запоминание состояния при рестарте, то тут уже и без новых элементов в интерфейсе не обойтись, так что это не сейчас. Но в целом, согласен, что может быть полезно, спасибо за feature request.
Можете пояснить, в каком виде представляете эту обертку?
Если я правильно понял идею, то: если не хочется закрывать соединения, просто не закрываете Nerdlog, и все. Т.к. Nerdlog - терминальное приложение, оно будет работать с любым терминальным мультиплексором (типа tmux или screen); так что можно держать несколько открытых nerdlog-ов, если хочется. Я не знаю, какие подобные мультиплексоры есть в Windows, но наверняка есть что-то подобное.
Ну и, конечно, можно просто держать открытым и один экземпляр nerdlog, подключенный сразу ко всем серверам, которые вам часто нужны.
MacOS не серверная, но прочитать логи из localhost все равно удобно. Когда я этот проект только что опубликовал, несколько человек сразу сказали, что хотят поддержку localhost без ssh.
С gawk - да, есть такое, хорошо бы добавить поддержку POSIX awk. Но sqlite тут не заменит gawk (т.к. в индекс-файле, о котором идет речь, нет данных из логов - там только таймстампы и соответствующие номера строк и смещения).
Если же вы имели в виду вкачивать все данные из логов в sqlite, то это уж точно перебор для Nerdlog. И место на диске двойное будет занимать (существенно, если размер файл логов измеряется в гигабайтах, как было в нашем оригинальном случае). И для поддержки journalctl пришлось бы тогда все данные оттуда вычитывать сначала, а journalctl медленный, так что это первоначальная инициализация этой базы данных займет кучу времен.
Самая фишка этого проекта в том, чтобы не усложнять больше необходимого, и использовать простые текстовые файлы как "базу данных".
В общем, можно ли так сделать - можно. Но вот стоит ли - я не думаю.
Технически, можно. Но вы действительно думаете, что это того стоит? Еще и сделать так, чтобы работало не только на Linux, но и BSD и MacOS.
Для простого индекса по датам, как мне кажется, простой текстовый файл достаточен, и усложнять вещи незачем. KISS и все такое.
Спасибо конечно, но сразу знать абсолютное смещение в файле все равно ведь быстрее, чем пропускать строку за строкой, даже с "шитими файлами" (Кстати, не слышал такого термина раньше, и не гуглится ничего по теме. Но из вашего описания понял, о чем речь)
Вы правы, в этом простом примере можно (и даже без флага
-f
можно - этот флаг нужен только если мы хотим читать сам awk-скрипт из файла). В реальности в Nerdlog так не получится, т.к. ему нужно будет отсечь ненужные части логов с помощью tail и head и уже результат обработать в awk, но да, в этом примере можно. Поправлю.Потому, что тогда sqlite должен быть установлен на всех хостах, с которых мы хотим читать логи. Цель была - использовать только GNU утилиты, предустановленные почти везде, чтобы Nerdlog работал из коробки.
Хмм, я не завсегдатай на Хабре, и, похоже, неправильно понял предназначение этого хаба: был почему-то уверен, что он для любых небольших утилит и т.д., но сейчас вижу, что это про конкретный фреймворк. Извиняюсь! Нужно было осмотреться получше.
Убрал его из статьи, спасибо, что указали!
Пока что просто в open source, значит. Если считаете, что статья хорошо подойдет в какие-то другие хабы, буду рад совету. Я еще думал про DevOps (т.к. знаю пару devops инженеров, использующих Nerdlog), но т.к. статья скорее про детали реализации, то сомневался про этот хаб, и пока не стал туда добавлять.
А, ну тогда это уже указано в доках (выделение мое):
И следующий параграф там также упоминает, что это можно решить синхронизацией логов на отдельный хост; rsyslog это умеет, насколько мне известно (но сам я не заморачивался. KISS и все такое).
Вы правы, но это следствие того же ограничения. На Github в этом пункте о дополнительной нагрузке на сервер также указано, что если сервер вообще не отзывается по любой причине, то и логи посмотреть не получится. Но наверное вы правы, что стоит упомянуть и про сценарий со вломом в этом же пункте (если взломщики были настолько аккуратны, что стерли свои следы из логов).
Вообще говоря, что именно делать с бэкап-токеном — каждый решает сам, со всеми вытекающими; и эта свобода (и, конечно, ответственность) мне нравится. Если есть желание периодически его перепроверять — можно держать его в сейфе, и это все равно (для меня) было бы значительно лучше, чем независимый токен, т.к. я совсем не хочу добавлять бэкап-токен вручную на каждый сервис.
Плюс к этому, в соседней ветке обсуждаем Trezor — если с ним все сработает, то я рассматриваю «замуровать в стену» не только девайс, но еще и seed phrase набитой на металлической пластине. Таким образом, даже если с девайсом по прошествии лет что-то случится, то все равно будет возможность его восстановить из seed phrase (можно было бы этим seed и ограничиться, но никто не знает, что станет с этой компанией Trezor впоследствии и насколько легко можно будет купить новый токен, так что предпочитаю просто иметь готовый бэкап-токен)
device_secret
будет выведен из seed phrase.Что ж, спасибо за полезный комментарий! Похоже, заказываю Trezor.
device_secret
и константу для увеличенияcounter
в U2F-токен было бы очень здорово, и это именно тот уровень поддержки от производителей токенов, которого я бы хотел видеть, рано или поздно. Опять же, не нужно будет доверяться производителям в том, что они не хранят у себя ключей.Такая возможность не решает вашей задачи иметь несколько ключей по подзадачам, но устраняет источник риска в виде электронного устройства.
(Только для хранения ключа (
device_secret
) вместо ламинированного листка бумаги я бы использовал что-то вроде этого + punch kit)Дело предпочтений, но я лично стараюсь воздержаться от использования телефонов и ноутбуков в качестве аутентификаторов; маленький USB-токен, который почти всегда при мне, вместе с другими ключами, и достается гораздо реже, чем телефон или ноутбук — более надежное решение.
По поводу остального — не вижу, как это делает материал в статье менее актуальным. И делегированное восстановление, и WebAuthn backup extension требуют поддержки со стороны Relying Party (RP), то есть сервисов, и в итоге сервисы могут поддерживать такое восстановление, а могут и не поддерживать. То есть, мы будем просто иметь больше неуниверсальных методов восстановления.
В статье же предлагается решение, совершенно независимое от сервисов; которое можно применить уже сегодня, и оно сразу оказывается рабочим для абсолютно всех сервисов, поддерживающих U2F.
Самое первое, что нужно сделать — это протестировать оба токена на demo.yubico.com/webauthn-technical: регистрируем основной токен, потом аутентифицируемся с ним же, проверяем, что
signatureCounter
низкий (видно, если раскрыть «Technical Details -> Response from the Relying Party»), потом аутентифицируемся с бэкап токеном, убеждаемся, что это работает, и чтоsignatureCounter
высокий.После этого можно удостовериться, что все работает и на настоящих сервисах. Берем какой-нибудь сервис (например, Google), добавляем туда основной токен, выходим, аутентифицируемся с основным токеном, выходим, аутентифицируемся с бэкап-токеном (убеждаемся, что это работает), выходим, пытаемся аутентифицироваться с основным токеном (убеждаемся, что это НЕ работает, т.к. бэкап уже засветился), после чего аутентифицируемся с бэкап-токеном, отзываем токен, и добавляем его заново (основной токен, конечно).
Я провел такую процедуру на нескольких сервисах, и для меня это было достаточным доказательством работоспособности бэкапа в принципе, так что я мог со спокойной душой его закапывать / замуровывать итд. Единственное, что не гарантируется — это аннулирование основного токена после использования бэкапа (т.к. сервис может игнорировать
counter
), но сам бэкап будет работать на всех сервисах.Что именно вы предлагаете, я так и не понял. Насколько понял — должен быть какой-то отдельный буфер, который будет заранее рассчитан на определенное количество задач. Уже это мне не нравится — гораздо лучше иметь просто связанный список, в который можно динамически добавлять/убирать сколько угодно дескрипторов.
Более того, в «официальном» TNKernel под Cortex есть архитектурные особенности, сохранять совместимость с которыми нет никакого желания:
RTOS для PIC32, пожалуй, поменьше, чем для Cortex, но хватает. API TNKernel не то чтобы уж необычный, но, тем не менее, перенести проект с TNKernel на TNeo — задача тривиальная, в то время как перенести с TNKernel на FreeRTOS — посложнее. Но ничего невозможного, конечно, нет.
Ну и насчет полезности обществу — простите, если, написав TNeo, я не был достаточно полезным для вас. Я, кстати, думал про блог «я пиарюсь», но решил все-таки написать сюда, т.к. статья, как мне кажется, содержит достаточное количество информации, которая может быть интересна даже тем, кому ни с TNeo, ни с FreeRTOS работать в жизни не придется.
Сорри, конечно, имелось в виду, наоборот: сохраняются только «caller-saved» регистры, т.е. те, которые должна сохранять вызывающая функция. А о «callee-saved» регистрах как раз позаботится сам ISR.
Ваши доводы насчет таймеров звучат разумно, спасибо. И если включен динамический тик, используется именно такая реализация (потому что там уже и нет периодических тиков, чтобы в них что-то декрементить).
Через год, я уже не очень хорошо помню, почему решил сделать статические таймеры именно так. Возможно, я был просто под впечатлением от реализации в Linux, и хотел сделать похожим образом. Может, переделаю в будущем.
Подход, о котором вы говорите, как о «правильном» (в противоположность моему, «наивному») — это как раз Segmented aproach, когда обработка прерываний разделена на два этапа. В ядре Linux эти два этапа называют top half и bottom half. Тогда, действительно, можно сделать так, что РТОС никогда не запрещает прерывания (как, например, AVIX-RT или Q-kernel).
Но написание приложения под эти два разных типа РТОС существенно отличается (под «Segmented» писать сложнее, подробности в статье по ссылке выше), и, поскольку мне нужна РТОС, максимально совместимая с TNKernel, то этот вариант я не особо рассматривал.
Я не сомневаюсь, что существуют приложения жесткого realtime, где запрещение прерываний недопустимо. В таких проектах, конечно, нужно использовать что-то вроде AVIX-RT. Но мне, честно говоря, несколько десятков тактов под запрещенными прерываниями никогда не мешали, и таких приложений, по-моему, большинство. Плюс к этому, «Segmented» добавляет оверхед к переключению задач. Процитирую заключение из статьи:
Можно было бы и закончить, но на некоторые вещи отвечу отдельно:
При обработке прерывания, TNeo сохраняет только «callee-saved» регистры, т.е. те, которые должна сохранять вызываемая функция, если эти регистры ей нужны. Если не сохранить их при обработке прерывания, то данные в них будут потеряны. На MIPS TNeo сохраняет их самостоятельно, а, например, Cortex-M делает все за меня, там ядро вообще ничего не делает при обработке прерывания.
Тут я с вами соглашусь, и даже вот дам вам ссылку на мой собственный пост на форуме Microchip, где я выражаю ту же идею. Но, первое: как мне там ответил товарищ andersm, эта функциональность довольно стандартна. И второе: мне эта функциональность не мешает, хоть я ее никогда и не использую, так что, чтобы не ломать без надобности совместимость с TNKernel, эти сервисы были оставлены.
Ну так, data queue именно для этого и нужны, да.
Ну то, что вы не стали разбираться и написали об этом, по-моему, вам чести не делает. А реализация таймеров, тем временем, описана даже в статье выше: основная идея позаимствована из ядра Linux, и она более эффективна, чем «просто сортированная очередь».
В TNeo есть жесткие таймеры. А мягких (пока) нет, т.к. лишняя задача в контексте вытесняющей ОС — это, как минимум, два переключения контекста каждый раз, и еще, как минимум, несколько сотен байт для ее стека. RAM в моих проектах — очень дорогой ресурс. Может, в будущем добавлю опционально, но пока мне ни разу не было нужно. Если нужно по таймеру разбудить какую-нибудь задачу, то можно из «жесткого» таймерного коллбэка семафором посигналить, или сообщение в очередь отправить.
Насчет этого ответил в самом начале комментария.
После прочтения этого, стало ясно, что мы с вами, возможно, совсем о разных классах систем говорим. Смартфон на Андроиде — это ведь эмбеддинг, и тупой экранчик в заряднике, на камне с 1 кБ RAM — тоже эмбеддинг.
Что значит «лучше не давать юзеру»? В эмбеддинге, РТОС и код приложения очень часто выполняется с одинаковым приоритетом — приоритетом ядра. Так что нет никакой защиты памяти, ничего такого. Это не тот класс систем. Можно, конечно, и на тостер Linux ставить, но это слишком дорого. Так что тут юзер имеет все возможности выстрелить в ногу, и никто ему не поможет.
Синхронизация делается мютексом — отлично. Только не всегда разумно: если нам нужно произвести очень короткое действие (пусть, например, банально поработать с GPIO), то мютекс — это просто колоссальный оверхед, в десятки раз превышающий длительность полезной работы. Мютексом можно ограничивать только сравнительно длительные операции (работа с внешней флешкой, например).
Именно так, через цепь тредов и проверяется, что непонятного. Да, это занимает время, и именно поэтому я это использую только в отладочной сборке. Осознание того, что у меня там лишние пару десятков тактов будут потрачены на это, меня не пугает — скорости хватает. Будет не хватать — выключу эту опцию в сборке.
«дедлоки это у студентов в учебниках» — да уж, рубанули с плеча. Дедлок возникает, если блокировать несколько ресурсов в разной последовательности. В условиях ограниченных ресурсов микроконтроллеров, часто бывает более разумно просто спроектировать систему так, чтобы задачи там блокировали ресурсы только в одной и той же последовательности, вместо того, чтобы обрабатывать ситуацию, когда мы не можем захватить очередной мютекс, поэтому нужно освобождать захваченный в данный момент, и т.д.
Если это правило нарушается, то может возникнуть дедлок, и ядро мне об этом тут же скажет. На сегодняшний день, эта возможность помогла мне ровно один раз (помогла быстро найти ошибку) — что ж, уже неплохо.
Если почувствуете необходимость ответить — пишите на почту (у меня на сайте есть адрес), я скопирую сюда.