Вот такая незатейливая игрушка на логику. Прошёл её за 181 команду. Говорят, можно меньше. Но сама идея понравилась очень.
http://www.poparcade.net/swf/light-bot-2205.swf
Вот такая незатейливая игрушка на логику. Прошёл её за 181 команду. Говорят, можно меньше. Но сама идея понравилась очень.
http://www.poparcade.net/swf/light-bot-2205.swf
Сделал первый патч для проекта OpenWatcom.
Пофиксил баги в утилите exe2bin, без которой дальше не мог писать вторичный загрузчик. Ну, заодно, и добавил пару нужных лично мне фич. Баг был серьёзный — buffer overflow, связан с тем, что линкер помещает в relocation table записи в неотсортированном порядке.
Целый день потратил на поиск ошибки. Открыл баг, выложил патч, жду подтверждения…
Выпущен июньский релиз ядра под названием jun.2008 Fishes: Pike.
Основные нововведения релиза:
- Добавлена информация о лицензиях.
- Добавлена поддержка PS/2 мыши (экспериментальное).
- Добавлено обнаружение и чтение ATA-устройств в режиме PIO.
- Добавлено устройство /dev/apic/local, ссылающееся на Local APIC.
- Добавлено устройство /dev/apic/timer, ссылающееся на Local APIC Timer.
- Добавлено устройство чтения шины PCI /dev/pci (экспериментальное).
- Добавлены функции sys_* для будущей защиты функций k_* от хаков из user-space.
- Добавлена возможность классом TConsole выводить данные в порт COM1.
- Добавлен класс трассировки ввода-вывода в аппаратные порты для возможности получения лога протокола обмена с устройством.
- Добавлен шлюз 0×07:0×00000000 для организации системных вызовов.
- Добавлены макроопределения для вывода отладки непосредственно в порт COM1.
- Добавлен класс быстрых мьютексов (фьютексов) для возможного исключения взаимоблокировок при разделении ресурса между задачей и обработчиком прерывания.
- Добавлено простое разделение нагрузки между процессорами в SMP.
Изменения:
- Исправлены ошибки в первичном загрузчике, связанные с неправильным кэшированием таблицы FAT.
- Все существующие до этого функции sys_* были переименованы в функции k_*.
- Заменён планировщик на планировщики, ориентированные на SMP.
- Исправлены ошибки в драйвере floppy.
- Исправлены ошибки в хранении данных текстового режима.
Как был такой анекдот:
Когда-то студент подумал. Ему понравилось, и он подумал ещё раз.
В общем, тут удалось пару часиков прикорнуть, и, о чудо, я, кажется додумался, как можно организовать блокировку прерываний для общего ресурса.
В чём суть? Да в том, что прерывание, вызываемое через interrupt gate, обладает свойством атомарности на процессоре. То есть, не произойдёт никаких других прерываний от внешних устройств, пока сброшен флаг IF (ситуации с исключениями в расчёт не берём).
Ситуацию с прерываниями мы научились решать. Если вектор прерывания доставляется всем процессорам, то чтобы заставить его обработать только один процессор, необходимо воспользоваться Try-Lock конструкцией:
в обработчике прерываний:
TMutex Mutex;
interrupt_handler:
if (Mutex.TryLock()) // Защита от запуска обработчика на других процессорах
{
// Обработчик прерывания
Mutex.Unlock(); // Разблокировка мьютекса
}
Таким образом, код обработчика выполняется тем процессором, который первым смог захватить объект Mutex (напомню, метод TryLock() — это блокировка без ожидания. То есть, если не удалось заблокировать мьютекс, то сразу же функция возвращает false, удалось — true).
Хорошо. Теперь необходимо решить обратную задачу. Необходимо параллельный код превратить в последовательный. Для этого достаточно воспользоваться некоторой модификацией приведённой ранее схемы.
В данном случае надо уже использовать не попытку блокировки ресурса, а уже полноценную блокировку с ожиданием, но при этом гарантировать, что обработчик и задача будут вызываться на разных процессорах. Осуществить это можно, как я уже говорил, сведя задачу к обработчику прерывания. А отличие между ними очень небольшое: в обработчике флаг IF сброшен, а в задаче — установлен. Поэтому код блокировки ресурса задачей надо обернуть в CLI + STI блок.
Итого получим асимметричную схему блокировки объекта Mutex1:
в обработчике прерывания:
if (Mutex.TryLock()) // Защита от запуска обработчика на других процессорах
{
// Обработчик прерывания
Mutex1.Lock();
// Код, использующий общие данные, требующие блокировки
Mutex1.Unlock(); // Разблокировка мьютекса блокировки данных
Mutex.Unlock(); // Разблокировка мьютекса прерываний
}
в задаче:
_asm cli; // Запрещение прерываний, мы как бы в обработчике
Mutex1.Lock();
// Код, использующий общие данные, требующие блокировки
Mutex1.Unlock(); // Разблокировка мьютекса блокировки данных
_asm sti; // Разрешение прерываний, мы как бы вышли из обработчика
Вот, в принципе, и всё решение, которое гарантирует, что:
1. Обработчик прерывания и задача будут выполняться одновременно на разных процессорах.
2. Код доступа к общим данным будет выполняться последовательно в зависимости от того, кто первым захватил ресурс.
UPD:
Соответственно, всё это выполняется в Kernel Mode (ring 0), а для асимметричной блокировки можно написать отдельный специальный класс блокировки.
То, что работает на одном процессоре, может гарантированно не работать на нескольких.
Стоило мне только разделить нагрузку между процессорами, и драйвер клавиатуры+мыши стал глючить.
В чём же прикол? А вот в следующем:
1. на одном проце задачи пытается модифицировать содержимое портов.
2. на другом проце в это время срабатывает прерывание, которому тоже нужны порты.
Следствие: оба проца пытаются биться за один и тот же порт.
Как разрешить данную ситуацию?
1. Ввести мьютекс и блокировать его при попытке обращения к портам. Данный метод очень опасен. Например, в случае, если обращение к портам со стороны задачи и прерывание происходят на одном и том же процессоре. В таком случае Dead Lock обеспечен.
2. Разрешить прерывания в обработчике. Опасна эта вещь повторной входимостью а также Dead Lock’ом, так как в случае однопроцессорной системы не будет приходить прерывание от таймера, пока не будет послан EOI в PIC. Если же слать EOI при входе в обработчик, Dead Lock так же обеспечен (повторная попытка заблокировать мьютекс).
3. Блокиовать прерывания от устройства-инициатора прерываний на время его программирования. Также чревато тем, что, возможно, ответ от устройства приходит именно с прерыванием.
Таким образом, все виды блокировок являются недопустимыми из-за их неполноценности. Обдумываю возможные другие варианты…
Задача: написать shell-скрипт, который выкидывает в файл список файлов в директории, претерпевших изменение после такой-то даты. Я придумал такую конструкцию:
find . -type f -printf «%TY-%Tm-%Td %TH:%TM:%TS %p\n» | awk ‘{ if (sprintf(«%s %s», $1, $2) > «2008-03-24 20:00:00″) { printf(«%s», $3); for (i=4; i<=NF; i++) printf(» %s», $i); printf(«\n»); } }’ >out.txt
Интересно, есть ещё какие-нибудь «более красивые» варианты?
Что-то сдаётся мне, я стал терять внимательность. Багу искал очень долго и, наконец, мегазавихляцким методом нашёл её. А ошибка была такая дурная, что аж обидно. Итак, вопрос на засыпку: какая ошибка в этом коде:
bool TATADirectory::ReadPIO(void *buffer, size_t count)
{
if (WaitInterrupt(ATA_PIO_TIMEOUT))
{
if (WaitDevice(ATA_PIO_TIMEOUT, ATA_SR_DRQ))
{
TIntHandler::ClearInterrupts();
inportwv(FPort.GetAddress()+ATA_REG_DR, buffer, count);
TIntHandler::SetupInterrupts();
return true;
}
}
return false;
}
Вот все всегда задумываются, как лучше всего организовать свою собственную рекламу? Одни придумывают слоганы, вторые организуют якобы бесплатные подарки (цена которых включена в стоимость товара, за который дают подарок
))), третьи покупают/подкупают СМИ, а четвёртые… А четвёртые придумывают оригинальные, полезные и приятные решения, и хороший пример тому — Intel.