LINUX.ORG.RU

Сообщения KivApple

 

Инициализация глобальных переменных в C++

Форум — Development

Допустим, есть такой код на C++:

ClassA a;
ClassB b(a);
ClassC c(a, b);

Насколько он корректен и нет ли тут UB? Я знаю, что если a, b и c находятся в разных compilation unit, то это будет UB (это логично - линковщик может слинковать файлы в произвольном порядке из каких-то своих соображений и особенности реализации). Но если речь идёт об одном файле? Интересует именно соответствие стандартам, а не только реальное поведение компиляторов (чтобы быть уверенным, что такой код не отвалится в будущем).

 

KivApple
()

Приложение для борьбы с прокрастинацией

Форум — Talks

Хочу такое приложение, чтобы там можно было создавать задачи и строить планы на будущее. При этом:

1) Можно создавать задачи на конкретную дату/время. Типа какой-то встречи. Также можно создавать периодические (ежедневные, еженедельные) задачи. Типа работы или учёбы.

2) Можно создавать задачи без привязки к конкретному времени. Возможно, с дедлайном (сделать в любое время, но не позднее такого-то дня), возможно, без него.

3) Задачи могут иметь подзадачи. И вообще всё это ещё может иметь приоритеты («важность» - «срочность» определяется и так исходя из даты дедлайна). При этом на подзадачи влияет важность родительской задачи.

Приложение должно анализировать все эти задачи и пытаться их распланировать так, чтобы я всё успел.

То есть я должен открывать телефон/доставать ноутбук и приложение радостно встречает меня текстом «Привет %username%. Сейчас такая-то дата, такое-то время. Через два часа тебе надо идти в универ, а сейчас тебе стоило бы заняться доработкой проекта по фрилансу».

Разумеется, задачи должно быть можно пропускать. Типа позанимался чем-то полчаса-час, нажал кнопку и приложение предложило новую задачу. Как советуют - делать смену деятельности, сначала фигачишь сложную и важную задачу, когда устал переключаешься на простые и неважные для отдыха, затем возвращаешься к важной.

Также было бы забавно, если бы приложение ещё планировано сон, в том числе с применение полифазной техники (несколько кусков в разное время суток), но это уже совсем опцианально. К тому же надо как-то рассчитать, чтобы я в это время хотел спать и быстро заснул, а то лишь время зря будет потеряно. Разве что тут прикрутить какое-то машинное обучение...

Есть что-нибудь готовое на эту тему?

 

KivApple
()

Идея для стартапа

Форум — Talks

Помните панику насчёт уязвимости Bad USB? Тогда никто не догадался до очевидного решения, предлагали ввести цифровые подписи устройств и прочие банальные ограничения.

Что вы думаете про коробочку, которая одним концом втыкается в компьютер, а другим в флешку (точнее флешка втыкается в неё)? А эта коробочка анализирует все USB-пакеты, проходящие через неё, по заложенным в себя правилам и производит их модификацию или даже отказ передачи, если захочет. Разумеется, производитель предоставляет пресеты для всех популярных вариантов фильтров, возможность быстро их переключать (возможно, даже залить в коробочку несколько профилей и менять их тумблером на корпусе) и т. д.

С ходу вижу три возможных сценария:

  1. Защита от классического Bad USB. Два пресета — «порт для флешек» и «порт для HID-устройств». В первом случае коробочка портит все попытки девайса прикинуться клавиатурой или мышкой (достаточно анализировать SETUP-пакет запроса дескриптора и банить устройство, если это дескриптор HID). Во втором случае коробочка портит все попытки девайса прикинуться флешкой. В идеале составное устройство не должно полностью отваливаться, а только то, что заблокировано (можно просто подпортить кусок дескриптора, чтобы лишние конечные точки не определились хостом, но в целом устройство успешно прошло енумерацию).
  2. Защита наоборот. Доверенной флешки от недоверенного хоста. Самое банальное — перевод флешки в read only. Перехватываем все команды записи и возвращаем хосту какую-нибудь ошибку. Ведь очень часто бывают ситуации, когда на флешку писать нафиг не нужно. Например, если вы хотите показать с неё презентацию или распечатать документ. А компьютеры в общественных местах очень часто заражены целым зоопарком вирусов (самое неприятное — вирус, который заменяет все папки ярлыками на вирус, а сами папки скрывает).
  3. Немного притянуто за уши. Допустим, мы хотим разрешить мыши и клавиатуры, но запретить флешки, модемы и т. д. Или разрешить только по белым спискам серийников. Понятное дело, что это можно сделать средствами ОС. Но так то прикольнее. Засунуть в системник такую коробочку и вывести все USB-порты через неё. Системник опечатать. Поскольку ПО такой коробочки значительно проще целой ОС, то и шанс что там есть уязвимость меньше.

Возможны другие варианты, но они не пришли мне в голову.

Техническую сторону вопроса я и так знаю, про неё особо не интересно. 2 USB PHY + FPGA на первом этапе, ASIC на втором. Кстати, себестоимость вроде выходит в пределах 1000 рублей даже в первом случае. Интересно мнение с точки зрения потребителей.

 badusb,

KivApple
()

Реализация очередей и не только

Форум — Development

Допустим, есть структура очереди. В неё можно читать и из неё писать. Объём памяти, выделенный под очередь, фиксированный (задаётся при создании). Очередь в себе хранит указатели на первый и последний элемент (при этом если мы доходим до конца массива во время чтения или записи, то переходим к его началу). Всё хорошо работает, однако возможна ситуация, когда в очереди кончится свободное место. В этом случае надо дождаться, пока оно появиться. Аналогично мы можем хотеть считать из очереди N байт, а если их не хватает, то дождаться их появления.

Busy loop это не круто. Однако у меня есть специальный примитив синхронизации - EventSource. Он поддерживает две основные операции - ожидание сигнала и отправка сигнала. Если поток ждёт сигнал, он не потребляет ресурсы. Отправка сигнала пробуждает все ждущие потоки.

На Linux реализуется этот примитив через pthread_condvar (параметр mutex не используем, передавая свежий mutex, который уничтожаем сразу же после вызова). Под моей личной RTOS реализуется нативно.

Теперь поступаем просто - после каждой записи или чтения посылаем соответственно сигнал о записи или о чтении. Если записали/прочитали не всё, что хотели, то ждём противоположный сигнал (если хотим записать, ждём пока кто-то прочитает, если хотим прочитать, то ждём, пока кто-нибудь запишет).

Возникает логичная проблема. А что если мы отправим сигнал о, скажем, записи. В этот момент нас нагло прервёт проснувшийся поток, который ждал, пока появятся данные в очереди (и мы его разбудили), вытащит из очереди все данные, пошлёт сигнал чтения, а затем снова уснёт от их недостатка. И только теперь к нам возвращается управление и мы начинаем ждать событие чтения. А оно не придёт! Потому что тот кто хотел уже всё прочитал и ждёт, пока нового события записи, которое мы отправили ранее и больше не отправим, пока не запишем ещё.

И что с этим делать? Надо как-то научиться принимать сигналы из прошлого. Скажем, заведём флаг и будем сбрасывать его в false в начале каждой записи/чтения, а после окончания записи (либо если кончилось место/данные в очереди) устанавливаем в true флаг противоположного действия помимо отправки сигнала. В ожидание переходим лишь если флаг остался в false. Но это не поможет - нас могут прервать внутри самой функции ожидания, до того как она собственно начнёт ждать. И она точно также пропустит сигнал.

Конечно, в своей RTOS я могу что-то нахимичить (сделать проверку флага и переход в ожидание, если его нет, атомарным), но не в pthread же.

Как вообще такое надо делать?

Моя кривая реализация очереди, если что - https://github.com/KivApple/controllerFramework/blob/master/libraries/platfor...

 

KivApple
()

Баг GCC или что?

Форум — Development
[kiv@kiv-hp15r161nr ~]$ cat test.c
#include <stdarg.h>
#include <stdbool.h>

void func(va_list arg) {
        bool value = va_arg(arg, bool);
        (void)value; // Нужно, чтобы оптимизатор не выпилил предыдущую строчку,
                // в реальном коде value используется нормально.
}
[kiv@kiv-hp15r161nr ~]$ gcc -O2 -c -o test.o test.c
[kiv@kiv-hp15r161nr ~]$ objdump -d test.o 

test.o:     формат файла elf64-x86-64


Дизассемблирование раздела .text:

0000000000000000 <func>:
   0:   0f 0b                   ud2 

Если заменить bool на int во втором аргументе va_arg, то код получается валидный. Версия GCC 5.3.0. Аналогичная ситуация на arm-none-eabi-gcc той же версии (собственно, всё началось с того что я искал несуществующую ошибку в своём коде для STM32).

Что это? Я где-то нарушил стандарт? Почему компилятор не выдал ни одного предупреждения? Да ладно бы он просто сгенерировал кривой код - почему он вообще вставляет просто недопустимую инструкцию (то есть портит код абсолютно осознанно)? WTF?

P. S. Добавление опций -Wpedantic -Wextra ничего не меняет (компилятор не ругается ни на что). Невалидная инструкция генерируется при любом уровне оптимизаций (разве что с -O0 добавляются ещё инструкции для создания стекового фрейма).

 

KivApple
()

M4 и include guard

Форум — Development

Хочу реализовать include guard на m4. Чтобы если я сделаю m4_include несколько раз одного и того же файла, это не привело к генерации нескольких копий текста.

Гугление выдало следующую инструкцию - http://stackoverflow.com/questions/5346397/how-can-you-do-an-ifdef-guard-for-.... То есть по сути дела советуют сделать аналог того, что делают при использовании сишного препроцессора.

Я, конечно, не против, но и в CPP меня раздражала необходимость писать целых 3 строчки, да ещё и 2 раза писать одно и то же название guard-переменной. Одна опечатка и имеем глюк. Но в CPP иначе нельзя - ведь макроопределение не способно породить новый макрос. А вот M4 такое умеет.

Пишем:

m4_define(`REMOVE_QUOTES', $*)

m4_define(`DEFINE_ONCE', `m4_ifdef(`$1',,`
	m4_define(`$1',1)
	REMOVE_QUOTES(m4_shift($@))
')')

А затем в файлах я буду писать:

DEFINE_ONCE(__MY_COOL_FILE_H__, `
... тут идёт содержимое файла, возможно, с другими макроопределениями ...
')

Чтобы проще было экспериментировать запускал M4 без аргументов и печатал туда всякие разные команды и смотрел, что получается.

Для начала я выполнил такое объявление, как указано выше. А затем использую его:

DEFINE_ONCE(T,A)


        A

DEFINE_ONCE(T,A)


        A

DEFINE_ONCE(T,A)

Можно заметить, что M4 почему-то дал мне описать одно и то же второй раз (хотя T становится defined уже после первого вызова DEFINE_ONCE), а третий (и последующие) уже не даёт. Если я попытаюсь затем сделать новое описание (с другой guard-переменной), то такой проблемы уже не будет (даже второй раз ничего не объявиться).

Что я не так понял в синтаксисе M4?

 

KivApple
()

Си + M4

Форум — Development

Читал, что люди прикручивают M4 к C/C++, чтобы получить более гибкий препроцессинг и делать всякие интересные вещи. Но почему-то никто не рассказывает, как он это сделал.

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

Решение - вызывать cpp до или после m4.

Проблема вторая - мы ведь хотим по-прежнему видеть красивые сообщения об ошибках с правильным указанием строки, где она случилась?

Решение - у m4 есть опция командной строки -s, которая включает генерацию специальных меток, которые помогут в этом деле компилятору (точно такие же метки вставляет и штатный препроцессор).

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

Как решить эту проблему? Я вижу два возможных решения:

1) Как-то заставить M4 эмулировать CPP. Возможно, написав несколько макросов (однако вроде как нельзя объявлять макросы, начинающиеся с #, точнее можно, но вызывать их нужно по-особому).

2) Как-то сделать так, что номера строк будут сохранять актуальность.

UPD: Хорошая новость - CPP понимает метки строк, поставленные до него. То если запускать CPP после M4, метки строк будут верными. Я выяснил это эмпирически. Можно получить доказательство, что это так? Однако получается, что m4 не будет применяться к файлам, которые мы инклюдим с помощью #include. Окей. Допустим, во всём проекте будет использоваться m4_include для всех модулей. Однако как теперь определять зависимости сборки? Сейчас я использую gcc -MM.

 , ,

KivApple
()

SDL + Android

Форум — Development

Хочу попробовать использовать SDL для разработки Android-приложения. В принципе разобрался со сборкой и нормально собираю APK.

Для теста написал простое приложение, которое после инициализации тупо крутит event loop в ожидании события SDL_QUIT (после чего вызывается SQL_Quit и функция main выходит). В свободное время экран просто заполняется белым цветом.

Всё работает, но возникла проблема с выходом. Я получаю белый экран, но приложение банально не реагирует на кнопку «назад». Единственный способ выйти - свернуть его и смахнуть в сторону в списке недавних приложений.

Окей. Гуглим, как в SDL определить нажатие кнопки «Назад». Узнаём, что в данном случае приходит событие SDL_KEYDOWN с определённым кодом. Обрабатываю это событие так же как SDL_QUIT - выхожу из event loop.

Теперь приложение нормально закрывается при нажатии на кнопку «Назад». Однако после этого оно отказывается запускаться, пока не смахнёшь его из списка недавних приложений.

Наконец, можно добавить перед return 0 в код main вызов exit(0). Тогда приложение нормально закрывается и нормально стартует заново после этого.

Но, насколько я понимаю, это очень криво с точки зрения Android. К тому же анимация закрытия не отрабатывает - приложение закрывается мгновенно.

Как правильно реализовывать выход из приложения на SDL на Android?

UPD: В некоторых туториалах советуют добавить ручной вызов finish для activity в конец метода run класса SDLMain (точнее не прямой вызов, а различными ухищрениями выполнить вызов finish в UI-потоке). Так вот - это не помогает. Точно также получаю результат, что приложение закрывается, а потом не открывается, пока его вручную не прибить. Да и вроде как в текущей версии кода Java есть ожидание завершения потока SDL и вызов после этого finish. То есть проблема не в том, что Activity не завершается, а в том что приложение после этого попадает в странное состояние, в котором оно продолжает висеть в памяти, но больше не способно запуститься.

 ,

KivApple
()

Стоит ли использовать PoE?

Форум — Admin

Наконец-то провёл себе нормальный кабельный интернет. Дано:

  1. Кабель от провайдера, входящий в квартиру, длина примерно 10 метров. 4-жильный, то есть, как я понимаю, больше 100 МБит по нему не получить.
  2. Wi-Fi роутер. Не умеет PoE. Штатный БП выдаёт 12 В 1.5А, если верить табличке на нём.
  3. Тариф 100 МБит/сек. Реально выдаёт 80-90 МБит на торрентах, так что хотелось бы эту скорость сохранить.

Роутер сейчас стоит весьма неоптимально - в углу квартиры и в некоторых местах плохо ловит (работает, но не даёт больше 10-15 МБит). Планирую его перенести в геометрический центр квартиры (примерно, конечно, он будет висеть на стене в коридоре). А розетки там нет. Значит её придётся делать. В принципе не проблема, но хочется сделать всё максимально красиво.

И тут мне пришла в голову гениальная идея. Берём вот такую штуку - http://tinyurl.com/z8mcmxj (это прямая ссылка на картинку, просто очень длинная, поэтому решил её укоротить). Провод от провайдера сматываем в рулон на входе в квартиру и втыкаем через переходник «мама»-«мама» в PoE Injector. Туда же втыкаем штатный БП от роутера, благо разъём вроде совпадает. На выход инжектора втыкаем уже гигабитный провод (ибо для PoE нужно 8 проводников, а не 4). Где-то метров 5-10 (некоторый запас, конечно же). Этот провод аккуратно проводим к роутеру. Там ставим PoE Splitter. Ну и сразу и питаем роутер и подаём туда интернет. Не вижу причин, чтобы это вообще не заработало, но есть вопросы.

Стоит ли? Не ухудшится ли качество сигнала? Понятное дело, что PoE задействует другие линии кабеля, не сигнальные. Однако:

  1. Возрастает количество соединений. Сейчас это только одно соединение - кабель провайдера -> роутер. А ведь будет кабель провайдера -> переходник «мама»-«мама» -> PoE Injector -> гигабитный кабель -> PoE Splitter -> роутер. Это сильно плохо?
  2. Общая длина кабеля возрастёт метров на 10. То есть уже только в квартире будет 20-25 метров. А ведь ещё он по подъезду до маршрутизатора провайдера идёт.
  3. Нормально будут передаваться на 10 метров 12В 1.5А по PoE?

Смогу ли я получить на такой конфигурации свои 100 МБит? Кабель будет аккуратно проложен в специальном лотке, а не замурован в бетонную стену.

 ,

KivApple
()

Импорт SQL-дампа в MongoDB

Форум — Web-development

Я знаю, что MongoDB - NoSQL, но задача специфическая.

Есть дамп базы данных из одной таблицы. Нет никаких связей между таблицами и прочих особенностей реляционных БД. Просто одна таблица с несколькими полями и огромной кучей записей. Нужно перегнать её в MongoDB.

Как это сделать минимумом телодвижений?

 ,

KivApple
()

Оцените потокобезопасность кода

Форум — Development

Есть вот такой код:

Thread * volatile threadQueue[TASK_SCHEDULER_MAX_PRIORITY + 1];
int threadMaxRunningPriority = 0;
Mutex threadQueueMutex;
Thread * volatile threadResumeQueue;
Mutex threadResumeQueueMutex;

void schedulerInit(void) {
	mutexInit(&threadQueueMutex);
	mutexInit(&threadResumeQueueMutex);
}

inline Thread *schedulerFindNextTask(void) {
	Thread *nextThread = NULL;
	if (mutexTryLock(&threadQueueMutex)) {
		for (; threadMaxRunningPriority >= 0; threadMaxRunningPriority--) {
			if (threadQueue[threadMaxRunningPriority] != NULL) {
				nextThread = threadQueue[threadMaxRunningPriority];
				threadQueue[threadMaxRunningPriority] = nextThread->nextScheduled;
				break;
			}
		}
		mutexUnlock(&threadQueueMutex);
	}
	return nextThread;
}

void schedulerResumeTask(Thread *thread);

void schedulerResumeDelayedTasks(void) {
	if (mutexTryLock(&threadResumeQueueMutex)) {
		while (threadResumeQueue != NULL) {
			Thread *thread = threadResumeQueue;
			if (__sync_bool_compare_and_swap(&threadResumeQueue, thread, thread->nextScheduled)) {
				schedulerResumeTask(thread);
			}
		}
		mutexUnlock(&threadResumeQueueMutex);
	}
}

void schedulerResumeTask(Thread *thread) {
	if (mutexTryLock(&threadQueueMutex)) {
		if (threadQueue[thread->priority] == NULL) {
			thread->nextScheduled = thread;
			thread->prevScheduled = thread;
			threadQueue[thread->priority] = thread;
		} else {
			thread->nextScheduled = threadQueue[thread->priority];
			thread->prevScheduled = thread->nextScheduled->prevScheduled;
			thread->nextScheduled->prevScheduled = thread;
			thread->prevScheduled->nextScheduled = thread;
		}
		if (thread->priority > threadMaxRunningPriority) {
			threadMaxRunningPriority = thread->priority;
		}
		mutexUnlock(&threadQueueMutex);
		schedulerResumeDelayedTasks();
	} else {
		do {
			thread->nextScheduled = threadResumeQueue;
		} while (!__sync_bool_compare_and_swap(&threadResumeQueue, thread->nextScheduled, thread));
	}
}

void schedulerSuspendTask(Thread *thread) {
	mutexLock(&threadQueueMutex);
	if (threadQueue[thread->priority] == thread) {
		threadQueue[thread->priority] = thread->nextScheduled;
		if (threadQueue[thread->priority] == thread) {
			threadQueue[thread->priority] = NULL;
		}
		return;
	}
	thread->nextScheduled->prevScheduled = thread->prevScheduled;
	thread->prevScheduled->nextScheduled = thread->nextScheduled;
	mutexUnlock(&threadQueueMutex);
	schedulerResumeDelayedTasks();
}

Поля структуры Thread nextScheduled и prevScheduled описаны как Thread * volatile.

Условия такие:

1) schedulerFindNextTask может прервать любую функцию, кроме самой себя. Ей допустимо иногда возвращать NULL вместо того, чтобы выполнить свою работу.

2) schedulerResumeTask может прервать любую функцию, в том числе саму себя. Она не имеет права блокироваться.

3) schedulerSuspendTask не может прервать никакую функцию, но два потока могут вызвать эту функцию одновременно. Допустима блокировка выполнения.

Больше никакой код к полям nextScheduled и prevScheduled, а также вышеописанным глобальным переменным не обращается.

1) Достаточно ли проверок и условий в этих функциях, чтобы гарантировать, что структура данных (связанный список) не будет никогда повреждена и не возникнет зависания (schedulerFindNextTask и schedulerResumeTask не имеют права блокироваться ни при каких обстоятельствах).

2) Можно ли доверять встроенной функции GCC __sync_bool_compare_and_swap на платформе ARM Cortex-M3?

3) Возможно ли переписать данный код более оптимально, сохранив безопасность?

 

KivApple
()

arm-none-eabi-gdb и указатели стека

Форум — Science & Engineering

У ARM Cortex-M3, как известно, есть два указателя стека - MSP и PSP. Первый для прерываний и когда PSP не настроен. PSP - для основного кода, если он настроен.

Как в GDB посмотреть содержимое стека PSP, если мы остановились на паузу внутри обработчика прерывания?

backtrace ожидаемо выводит стек вызовов по MSP. info registers показывает SP == MSP. А как узнать куда указывает PSP? А ещё лучше получить стек вызовов.

 , ,

KivApple
()

Отправка сообщений работает не всегда

Форум — Linux-org-ru

Сейчас отправка сообщений по возможности осуществляется модно-стильно-молодёжно с помощью AJAX или чего-то в этом роде. В итоге иногда я попадаю в ситуацию, когда ЛОР нормально открывается, но при попытке отправить сообщение получаю красный текст снизу формы отправки - «Не удалось отправить сообщение, попробуйте позднее» (повторные нажатия ничего не дают в обозримой перспективе). Отключаю скрипты и форма уходит на сервер человеческим POST-запросом - всё отлично работает.

Однако сидеть на LOR без JS тоже не очень - не сбрасывается счётчик просмотренных уведомлений, для отправки сообщения открывается новая страница. А эти фичи мне нравятся.

Не вижу какого-то особого профита от того, что сообщение отправляет скрипт через AJAX, а не POST-запрос, зато на плохом интернете (а быть может это таки баг движка, потому что проявляется далеко не всегда) это глючит.

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

Ну или, быть может, кто-то набросает user script для выпила данного функционала без отказа от остальных плюшек скриптов.

 

KivApple
()

Собственная Мини-RTOS

Форум — Development

Пилю я тут потихоньку свой фреймворк для микроконтроллеров (https://github.com/KivApple/controllerFramework) и дошёл до осознания того, что там обязательно нужна небольшая RTOS (разумеется, опциональная). Разобраться, как переключать задачи на ARM Cortex-M3 мне труда не составило (для M4, насколько я понимаю, надо просто добавить сохранение состояния FPU), но теперь встали некоторые архитектурные вопросы.

1) Реализация планировщика. Собственно как? Сейчас тупой алгоритм со сложностью О(N). Бежим по связанному списку процессов и ищем процесс с максимальным приоритетом, который при этом готов к исполнению. Переключаемся на найденный процесс.

int maxPriority = THREAD_PRIORITY_STOPPED;
Thread *thread = currentThread;
do {
	thread = thread->next;
	if ((thread->priority > maxPriority) && (threadReady(thread, tickCounter))) {
		maxPriority = thread->priority;
		nextThread = thread;
	}
} while (thread != currentThread->next);

Но это, вероятно, что-то не то. Нужна очередь с приоритетом. Типа извлекаем из очереди очередной процесс и переключаемся на него, а текущий процесс пихаем обратно в очередь. Если мы попали в планировщик раньше времени (обычно мы попадаем туда из обработчика SysTick), потому что процесс уснул - то не пихаем его обратно в очередь. Если мы хотим разбудить процесс (это делается в функции отправки сигнала процессу, а не в планировщике), то пихаем его в очередь. И тут я вижу множество разных вариантов реализации очереди с приоритетом - бинарная куча, полиноминальная куча, куча Фибоначчи, 2-3 куча... Какой из них следует выбрать? Какие алгоритмы применяются в других RTOS?

2) Как организовать запуск RTOS? Я создаю процесс с именем main и переключаюсь на него. Однако получается, что выполнение начинается с нового адреса, указанного юзером при инициализации RTOS. А существующие RTOS позволяют просто вызвать из main функцию типа start_rtos и дальнейший код автоматически продолжает исполнятся в рамках первого процесса. Как они так делают? Это получается надо весь текущий стек скопировать на место стека только что созданного процесса, а начинать с адреса возврата из функции инициализации (текущий стек обычно остаётся в качестве стека для прерываний)? Я туплю, как всё происходит.

 ,

KivApple
()

STM32F4 и USB

Форум — Science & Engineering

С низкоуровневой работой с USB на STM32F103 я разобрался, теперь очередь USB OTG, который присутствует на более жирных МК (например, STM32F407, который я и использую для всех тестов). Для начала мне вполне хватит device-only mode.

Инициализирую USB я так:

usb->globalRegs->GINTSTS = 0xFFFFFFFF;
usb->globalRegs->GUSBCFG |= OTG_FS_GLOBAL_FS_GUSBCFG_PHYSEL;
usb->globalRegs->GCCFG |= OTG_FS_GLOBAL_FS_GCCFG_PWRDWN | OTG_FS_GLOBAL_FS_GCCFG_VBUSBSEN;
while ((usb->globalRegs->GRSTCTL & OTG_FS_GLOBAL_FS_GRSTCTL_AHBIDL) == 0);
usb->globalRegs->GRSTCTL |= OTG_FS_GLOBAL_FS_GRSTCTL_CSRST;
while (usb->globalRegs->GRSTCTL & OTG_FS_GLOBAL_FS_GRSTCTL_CSRST);
uint32_t ahbFreq = stm32_rccAHBFrequency();
uint32_t trdt;
if (ahbFreq <= 15000000) {
	trdt = 0xF;
} else if (ahbFreq <= 16000000) {
	trdt = 0xE;
} else if (ahbFreq <= 17200000) {
	trdt = 0xD;
} else if (ahbFreq <= 18500000) {
	trdt = 0xC;
} else if (ahbFreq <= 20000000) {
	trdt = 0xB;
} else if (ahbFreq <= 21800000) {
	trdt = 0xA;
} else if (ahbFreq <= 24000000) {
	trdt = 0x9;
} else if (ahbFreq <= 27500000) {
	trdt = 0x8;
} else if (ahbFreq <= 32000000) {
	trdt = 0x7;
} else {
	trdt = 0x6;
}
usb->globalRegs->GUSBCFG = (usb->globalRegs->GUSBCFG & ~OTG_FS_GLOBAL_FS_GUSBCFG_TRDT_MASK) | OTG_FS_GLOBAL_FS_GUSBCFG_FDMOD |
	(trdt << OTG_FS_GLOBAL_FS_GUSBCFG_TRDT_OFFSET);
usb->deviceRegs->DCFG |= 3 << OTG_FS_DEVICE_FS_DCFG_DSPD_OFFSET;
usb->powerRegs->PCGCCTL = 0;
usb->globalRegs->GAHBCFG |= OTG_FS_GLOBAL_FS_GAHBCFG_GINT;
usb->globalRegs->GINTMSK = OTG_FS_GLOBAL_FS_GINTMSK_ENUMDNEM;
nvicEnableIRQ(OTG_FS_IRQ);
nvicEnableIRQ(OTG_FS_WKUP_IRQ);

Жду прерывание окончания энумерации. Оно приходит при втыкании кабеля USB. При приходе прерывания делаю вот такие вещи:

static void STM32USBDriverClass_resetFIFO(STM32USBDriverClass *usb) {
	usb->fifoTop = 0;
}

static uint16_t STM32USBDriverClass_allocFIFO(STM32USBDriverClass *usb, uint16_t count) {
	uint16_t r = usb->fifoTop;
	usb->fifoTop += count;
	return r;
}
...
int i;
for (i = 0; i < STM32USB_MAX_EP_COUNT; i++) {
	usb->deviceRegs->DIEP[i].CTL = OTG_FS_DEVICE_FS_DIEPCTL0_SNAK;
	usb->deviceRegs->DOEP[i].CTL = OTG_FS_DEVICE_DOEPCTL0_SNAK;
	usb->deviceRegs->DIEP[i].INT = 0xFF;
	usb->deviceRegs->DOEP[i].INT = 0xFF;
	usb->epInfo[i].inCallback = NULL;
	usb->epInfo[i].outCallback = NULL;
}
usb->deviceRegs->DAINT = 0xFFFFFFFF;
usb->deviceRegs->DAINTMSK = 0;
usb->globalRegs->GINTSTS = 0xFFFFFFFF;
STM32USBDriverClass_resetFIFO(usb);
STM32USBDriverClass_allocFIFO(usb, 128);
usb->globalRegs->GRXFSIZ = 128;
usb->globalRegs->GINTMSK = OTG_FS_GLOBAL_FS_GINTMSK_ENUMDNEM | OTG_FS_GLOBAL_FS_GINTMSK_RXFLVLM | OTG_FS_GLOBAL_FS_GINTMSK_IEPINT |
	OTG_FS_GLOBAL_FS_GINTMSK_OEPINT | OTG_FS_GLOBAL_FS_GINTMSK_USBSUSPM;
usb->deviceRegs->DIEPMSK = OTG_FS_DEVICE_FS_DIEPMSK_XFRCM;
usb->deviceRegs->DOEPMSK = OTG_FS_DEVICE_FS_DOEPMSK_XFRCM | OTG_FS_DEVICE_FS_DOEPMSK_STUPM;
usb->deviceRegs->DCFG = (usb->deviceRegs->DCFG & ~OTG_FS_DEVICE_FS_DCFG_DAD_MASK) | (0 << OTG_FS_DEVICE_FS_DCFG_DAD_OFFSET);
...
// bufSize == 64
bufSize = (bufSize + 3) & ~3;
uint32_t mpsiz;
if (bufSize >= 64) {
	mpsiz = 0;
} else if (bufSize >= 32) {
	mpsiz = 1;
} else if (bufSize >= 16) {
	mpsiz = 2;
} else {
	mpsiz = 3;
}
usb->deviceRegs->DOEP[0].SIZE = 0;
usb->deviceRegs->DOEP[0].CTL = mpsiz << OTG_FS_DEVICE_DOEPCTL0_MPSIZ_OFFSET;
usb->deviceRegs->DIEP[0].SIZE = 0;
usb->deviceRegs->DIEP[0].CTL = (mpsiz << OTG_FS_DEVICE_FS_DIEPCTL0_MPSIZ_OFFSET) | (0 << OTG_FS_DEVICE_FS_DIEPCTL0_TXFNUM_OFFSET);
usb->globalRegs->HPTXFSIZ = (STM32USBDriverClass_allocFIFO(usb, bufSize / 4) << OTG_FS_GLOBAL_FS_HPTXFSIZ_PTXSA_OFFSET) |
	((bufSize / 4) << OTG_FS_GLOBAL_FS_HPTXFSIZ_PTXFSIZ_OFFSET);
usb->epInfo[ep].rxBufSize = (3 << OTG_FS_DEVICE_DOEPTSIZ0_STUPCNT_OFFSET) | OTG_FS_DEVICE_DOEPTSIZ0_PKTCNT | bufSize;
usb->epInfo[ep].txBufSize = bufSize;
usb->epInfo[ep].outCallback = callback;
usb->epInfo[ep].outCallbackArg = arg;
usb->epInfo[ep].inCallback = callback;
usb->epInfo[ep].inCallbackArg = arg;
usb->deviceRegs->DAINTMSK |= (1 << OTG_FS_DEVICE_FS_DAINTMSK_IEPM_OFFSET) | (1 << OTG_FS_DEVICE_FS_DAINTMSK_OEPINT_OFFSET);
...
// ep == 0, dir == 0
volatile STM32OTGEpRegs *epRegs = (dir ? usb->deviceRegs->DIEP : usb->deviceRegs->DOEP) + ep;
epRegs->SIZE = usb->epInfo[ep].rxBufSize;
epRegs->CTL |= OTG_FS_DEVICE_FS_DIEPCTL0_EPENA | OTG_FS_DEVICE_FS_DIEPCTL0_CNAK;

На этом инициализация оканчивается. Я ожидаю получить прерывание по причине RXFLVL, что будет значить приход первого SETUP-пакета, однако ничего не получаю. Через какое-то время приходит SUSPEND, а затем новый RESET. И так повторяется несколько раз, пока хосту не надоест долбить устройство.

Что я делаю не так в настройке EP0, что устройство не получает ни одного пакета (никаких прерываний об ошибках тоже не приходит)? Проверял адреса полей всех своих структур, описывающих регистры USB OTG - с даташитом совпадают.

С частотами вроде всё тоже ок. При настройке коэффициентов PLL использую те же, что и libopencm3 (там USB работает с такими настройками) для случая кварца 8 МГц и выходной частоте 168 МГц.

 , ,

KivApple
()

Альтернативы штатному препроцессору Си

Форум — Development

Собственно, сабж. Си, в отличии от многих других языков, обладает весьма скудным встроенным макроязыком (и С++ тоже, но там хотя бы есть куча штатного сахара из коробки + шаблоны). Возможно, существуют какие-то проекты по исправлению этого недоразумения?

Мне нравится концепция Vala. «Компилятор» этого языка по сути конвертирует ООП-код в plain C. Но, увы, он гвоздями прибит к glib, что очень плохо. Нет ли подобных проектов, но без привязки к каким-либо библиотекам?

Мои хотелки - некоторый уровень синтаксического сахара. Хотя бы наследование структур. В идеале, конечно, классы с виртуальными методами. Всяких исключений, множественного наследования, RTTI и т. д. не нужно.

Нужна конвертируемость в Си и отсутствие лишнего кода, ибо хочется это использовать с микроконтроллерами.

 ,

KivApple
()

Сломался OpenVPN после обновления

Форум — Admin

Есть сервер на ArchLinux на базе CubieBoard2. На нём стоит сервер OpenVPN. Всё работало хорошо, а потом я обновился. Теперь клиент успешно подключается к серверу, но пакеты не ходят (скажем, пытаюсь попинговать внутренний IP сервера - 10.8.0.1 - не пингуется, внешний интернет тем более).

Таблица маршрутов до подключения к VPN:

$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         localhost       0.0.0.0         UG    600    0        0 wlan0
192.168.43.0    *               255.255.255.0   U     600    0        0 wlan0

Таблица маршрутов после подключения к VPN:

$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         localhost       0.0.0.0         UG    50     0        0 tun0
default         localhost       0.0.0.0         UG    600    0        0 wlan0
10.8.0.0        localhost       255.255.255.0   UG    50     0        0 tun0
localhost       *               255.255.255.255 UH    0      0        0 tun0
localhost       *               255.255.255.255 UH    50     0        0 tun0
192.168.43.0    *               255.255.255.0   U     600    0        0 wlan0
X.X.X.X  localhost       255.255.255.255 UGH   600    0        0 wlan0

Здесь X.X.X.X - публичный IP сервера.

В логах на сервере в момент подключения клиента:

Dec 14 08:05:10 suigintou-0 openvpn@server[197]: 188.162.251.3:6299 Control Channel: TLSv1.2, cipher TLSv1/SSLv3 DHE-RSA-AES256-GCM-SHA384, 2048 bit RSA                
Dec 14 08:05:10 suigintou-0 openvpn@server[197]: 188.162.251.3:6299 [unia] Peer Connection Initiated with [AF_INET]188.162.251.3:6299
Dec 14 08:05:10 suigintou-0 openvpn@server[197]: unia/188.162.251.3:6299 MULTI_sva: pool returned IPv4=10.8.0.6, IPv6=(Not enabled)
Dec 14 08:05:10 suigintou-0 openvpn@server[197]: unia/188.162.251.3:6299 MULTI: Learn: 10.8.0.6 -> unia/188.162.251.3:6299
Dec 14 08:05:10 suigintou-0 openvpn@server[197]: unia/188.162.251.3:6299 MULTI: primary virtual IP for unia/188.162.251.3:6299: 10.8.0.6
Dec 14 08:05:14 suigintou-0 openvpn@server[197]: unia/188.162.251.3:6299 PUSH: Received control message: 'PUSH_REQUEST'
Dec 14 08:05:14 suigintou-0 openvpn@server[197]: unia/188.162.251.3:6299 send_push_reply(): safe_cap=940
Dec 14 08:05:14 suigintou-0 openvpn@server[197]: unia/188.162.251.3:6299 SENT CONTROL [unia]: 'PUSH_REPLY,redirect-gateway def1 bypass-dhcp,dhcp-option DNS 10.8.0.1,route 10.8.0.0 255.255.255.0,topology net30,ping 10,ping-restart 120,ifconfig 10.8.0.6 10.8.0.5' (status=1)

188.162.251.3 - публичный IP клиента (это динамический IP мобильной сети, а все её клиенты сидят за NAT, так что не вижу смысла его не палить).

Конфиг OpenVPN: http://pastebin.com/LL8z6xPC

ifconfig на сервере:

# ifconfig tun0
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 100  (UNSPEC)
        RX packets 797  bytes 50784 (49.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

А это нормально, что у tun0 нет IP адреса? Я не помню был ли он раньше, но вообще IP сервера внутри OpenVPN - 10.8.0.1.

 

KivApple
()

KWin X11 иногда зависает

Форум — Desktop

Время от времени при работе в KDE возникает такая ситуация, что изображение на экране перестаёт обновляться. Мышка по экрану ездит, но с окошками взаимодействовать ею не получается. Аналогично с клавиатурой и другими устройствами ввода. При этом загрузка процессора и диска в пределах нормы, все приложения продолжают работать.

Можно переключиться на другую виртуальную консоль и прибить процесс kwin_x11, тогда всё отвисает, но окна лишаются декораций. Чтобы это исправить можно любым способом (скажем, через krunner) выполнить команду kstart5 kwin_x11. После этого можно продолжать нормальную работу. Но, знаете ли, это очень раздражает, тем более, что подвиснуть всё может в самый неподходящий момент.

В 99% случаев подвисание случается при появлении нового окна (допустим, я открыл файл в файловом менеджере или нажал Ctrl + S в браузере, чем вызвал диалог сохранения).

В логах (journalctl) есть лишь одна подозрительная строчка (остальные графической оболочки вообще никак не касаются), совпадающая по времени с моментом зависания:

QXcbConnection: XCB error: 3 (BadWindow), sequence: 25341, resource id: 62914561, major code: 18 (ChangeProperty), minor code: 0

Однако эта строчка встречается и в другие моменты, когда никаких зависаний не было.

Графическое оборудование моего ноутбука:

00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT Integrated Graphics Controller (rev 0b)
09:00.0 3D controller: NVIDIA Corporation GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (rev ff)

Блоб nvidia, а также bumblebee установлены и настроены (с Nouveau ноутбук не просыпался после ждущего и спящего режимов), но ни одного приложения с помощью optirun с момента последний загрузки до зависания запущено не было.

 , ,

KivApple
()

Глючит Wi-Fi

Форум — Linux-hardware

Имеется ноутбук. На нём есть Wi-Fi модуль:

0a:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8723BE PCIe Wireless Network Adapter

Всё работает хорошо - сети видятся, я могу подключиться. Однако может наступить такой момент, когда сеть отвалится - всё будет как обычно, но ни один пакет не будет доходить до роутера (или с роутера). ping и tracepath молчат. Достаточно переподключиться - и всё опять заработает.

При этом такие глюки как с железным Wi-Fi роутером, так и с ТД из ведройд-смартфона, а у другого ноутбука с этим точками доступа проблем нет.

Причём такое ощущение, что всё зависит от того, какой трафик идёт. Если читать ЛОР или смотреть видео (скажем, с YouTube), то может очень долго не будет глючить, хотя объём трафика в этих случаях будет заметно отличаться. Если вообще не трогать ноутбук, то с большой вероятностью интернет не отваливается часами. А, скажем, если скроллить ленту вконтакте, то может отвалиться очень быстро. То есть глюки не зависят от объёма трафика и времени, но от содержимого.

Ах да, в dmesg ничего странного не появляется, а вот интерфейс NetworkManager иногда при отключении соединения может подвиснуть на секунд 5, потом ещё написать что-то типа «device not active», но такое бывает не всегда.

Шо за фигня?

 

KivApple
()

Не прошивается STM32 через StLink

Форум — Development

Я пишу потихоньку свой фреймворк для программирования микроконтроллеров и столкнулся с проблемой. После прошивки программы, собранной моим фреймворком, становится невозможно загрузить прошивку через программатор - st-flash просто зависает. При этом через бутлоадер по-прежнему сохраняется возможность залить прошивку. А возможность отладки через StLink и GDB сохраняется (но если сделать load в gdb, то всё зависнет).

Что характерно, проблема проявляется только на STM32F103 - на STM32F407 всё работает отлично.

Если залить прошивку, собранную с другими библиотеками (скажем, libopencm3 или ChibiOS), то всё начинает работать.

Если запускать st-flash с ключом --debug, то можно видеть бесконечный вывод строки типа

2015-11-23T22:48:24 DEBUG src/stlink-common.c: *** stlink_read_debug32 3 is 0x4002200c

В чём может быть проблема? Я отладку не запрещал специально никакими регистрами, ножки не переназначал. Быть может, отладку надо наоборот в коде специально разрешить?

Кстати, если загрузить в бутлоадер (boot0 = 1), то программатор нормально шьёт. То есть именно как будто я что-то не инициализирую.

UPD: Интересно, 0x4002200c - это адрес статус-регистра контроллера Flash... Всё, что я делаю с контроллером флеш-памяти - это настраиваю задержку при активации PLL:

FLASH_ACR = (FLASH_ACR & ~FLASH_ACR_LATENCY_MASK) | FLASH_ACR_PRFTBE | ((outClk - 1) / 24000000);

Перемещено true_admin из science

 

KivApple
()

RSS подписка на новые темы