Это просто сочетание user-level спинлока и kernel-level примитивов, которые фактически останавливают тред. Дело в том, что спинлоки катастрофически быстрее мьютексов, но применимы только для очень коротких захватов, иначе они долго и бессмысленно жрут процессор. Поэтому делают так — сначала пытаются захватить спинлок (без ухода в ядро), если удалось — ура, мы обошлись малой кровью. Если спинлок занят то уходим в ядро на полновесный системный вызов, который усыпляет нас, пока спинлок не освободится.
Интереснее другое — если при каждом открытии спинлока надо дёргать ядро, чтобы сообщить, что пора разбудить ожидающих, то мы потеряли смысл мероприятия — всё равно по сисколлу на обращение к защищённой зоне. Иначе неясно, когда будить.
Разбираться неинтересно, но могу предположить, что если кто-то ждёт нашего запертого спинлока, то ядро переводит страницу со спинлоком в r/o и по пейджфолту выясняет, когда мы его отпираем.
Такая схема позволит работать вообще без обращений к ядру если коллизий не возникает, и иметь по одному обращению на нить на запирание, если коллизия.
Ну и да — обычно если спинлок занят, то до ухода в тяжёлый сисколл делают ещё несколько итераций в надежде, что спинлок вот-вот освободится.
Что есть спинлоки — напишу позже. Впрочем, Вы про них и так знаете.
Господа, пару лет тому назад я реализовал внутри ядра Фантома модуль поддержки API Kolibri OS. Но по документации понятно совсем не всё, и некоторые части API работают неидентично оригиналу. Плюс — нет сишного исходника для распаковщика приложений, поэтому загрузчик ест только распакованные исполняемые файлы. Но — некоторые программы работают.
Если бы в команде Колибри нашёлся кто-то, кто готов помочь доработать эту подсистему, наверное, было бы здорово. Если кому-то идея переносимой на другие платформы Колибри кажется интересной — дайте знать.
Оно и в Яве давно так, интерпретатор почти уже не используется. Можно её вообще скомпилировать в бинарник (gcj, part of gcc compilers collection). Как таковая среда — это библиотека. Если она не нужна, можно получить сишный размер программы.
Ограничивать ОС одним ЯП, да ещё и не самым популярным — затея спорная. Да и гарантии защиты памяти даёт не сам язык, а среда исполнения+генератор кода. В Фантоме виртуальная машина самодостаточна с точки зрения обеспечения надёжности, но это же всё равно промежуточный этап — дальше будет генерация бинарного кода из байткода (JIT), и ВМ как таковая исчезнет, останется только в виде промежуточного представления программы.
"между тем, как мы получили адрес, и тем, как мы увеличили счетчик ссылок, память могла быть освобождена." — одно из решений — откладывать ref deq и делать его в специальном потоке, остановив все остальные потоки в safe point. sape point делать через mem write access в страницу, которая переводится в read only, чтобы собрать всех обратившихся в page fault хендлере.
Проверка указателя на ноль вообще неясно, зачем нужна. Если, конечно, нулевое значение не является функциональным и что-то значит само по себе. Ничто не мешает размепить нулевую страницу и ловить такие пойнтеры на page fault.
Чёткой отсылки к номеру версии байткода в документации soot я не нашёл, но последний билд проекта — от 2012 года, что наводит на мысль, что явно не 8. Скорее 6, да.
Производительности я считаю правильным достигать через JIT, сохраняя регулярную структуру формальной виртуальной машины. Внутри кода JIT ничто не мешает пускаться во все тяжкие, уходя от навязанных виртуальной машиной представлений. Собственно, даже в интерпретаторе любая формула из группы интегральных переменных будет отработана в бинарном виде, преобразование инта в объектную форму происходит только при вызовах и сохранениях переменных.
Вызов статики пока не реализован, но проблем тут нет вообще. Есть два простых варианта. первый — генерировать для статики специальный класс, второй — тупо делать статические методы так же как обычные, держать для них синглтон инстанс this, и при кодогенерации запрещать доступ к полям this. Спасибо ещё раз за вопрос, заодно я, кажется, определился с реализацией. :)
Интерфейсы запроектированы. Реализация реально не дошла. Есть два варианта реализации. Первый. Предпочтительный. Реально все пойнтера виртуальной машины таскают с собой пойнтер на интерфейс, по которому и происходит обращение к vmt. Это позволит реализовать cast с заменой в пойнтере интерфейса на любой нужный. Дальше вызов по vmt[ordinal интерфейса]. Второй вариант совсем тупой — invokedynamic. Но он пока без полиморфизма. Что, впрочем, тоже решается легко — передавать сигнатуру вместо имени метода.
Я несколько раз задумывался над тем, чтобы уйти от С в разработке ядра Фантома. Думал и про D. Но остановило то, что в стандартной поставке gcc его нет. И в cygwin/mingw не входит. :(
Ну и, кроме того, там же написано — "мне известно". Наверняка на свете есть что-то, что мне неизвестно. :)
Неверно? Нет там флагов?
Судя по тому, что он у меня в дереве лежит, но пакованные программы не грузятся, что-то с ним не то… :(
Сигнатура — 'KPCK'?
О. Он даже подключен, оказывается. Здесь.
Интереснее другое — если при каждом открытии спинлока надо дёргать ядро, чтобы сообщить, что пора разбудить ожидающих, то мы потеряли смысл мероприятия — всё равно по сисколлу на обращение к защищённой зоне. Иначе неясно, когда будить.
Разбираться неинтересно, но могу предположить, что если кто-то ждёт нашего запертого спинлока, то ядро переводит страницу со спинлоком в r/o и по пейджфолту выясняет, когда мы его отпираем.
Такая схема позволит работать вообще без обращений к ядру если коллизий не возникает, и иметь по одному обращению на нить на запирание, если коллизия.
Ну и да — обычно если спинлок занят, то до ухода в тяжёлый сисколл делают ещё несколько итераций в надежде, что спинлок вот-вот освободится.
Что есть спинлоки — напишу позже. Впрочем, Вы про них и так знаете.
Господа, пару лет тому назад я реализовал внутри ядра Фантома модуль поддержки API Kolibri OS. Но по документации понятно совсем не всё, и некоторые части API работают неидентично оригиналу. Плюс — нет сишного исходника для распаковщика приложений, поэтому загрузчик ест только распакованные исполняемые файлы. Но — некоторые программы работают.
Если бы в команде Колибри нашёлся кто-то, кто готов помочь доработать эту подсистему, наверное, было бы здорово. Если кому-то идея переносимой на другие платформы Колибри кажется интересной — дайте знать.
Код здесь
Ограничивать ОС одним ЯП, да ещё и не самым популярным — затея спорная. Да и гарантии защиты памяти даёт не сам язык, а среда исполнения+генератор кода. В Фантоме виртуальная машина самодостаточна с точки зрения обеспечения надёжности, но это же всё равно промежуточный этап — дальше будет генерация бинарного кода из байткода (JIT), и ВМ как таковая исчезнет, останется только в виде промежуточного представления программы.
(Кстати, я и сишным-то фронтом clang ядро собрать не могу...)
Про invoke — откровенно говоря, не помню деталей. Давно делал ту версию. Вполне возможно, что мне тупо не пришло в голову опереться на тип invoke.
Чёткой отсылки к номеру версии байткода в документации soot я не нашёл, но последний билд проекта — от 2012 года, что наводит на мысль, что явно не 8. Скорее 6, да.
Производительности я считаю правильным достигать через JIT, сохраняя регулярную структуру формальной виртуальной машины. Внутри кода JIT ничто не мешает пускаться во все тяжкие, уходя от навязанных виртуальной машиной представлений. Собственно, даже в интерпретаторе любая формула из группы интегральных переменных будет отработана в бинарном виде, преобразование инта в объектную форму происходит только при вызовах и сохранениях переменных.
Вызов статики пока не реализован, но проблем тут нет вообще. Есть два простых варианта. первый — генерировать для статики специальный класс, второй — тупо делать статические методы так же как обычные, держать для них синглтон инстанс this, и при кодогенерации запрещать доступ к полям this. Спасибо ещё раз за вопрос, заодно я, кажется, определился с реализацией. :)
Интерфейсы запроектированы. Реализация реально не дошла. Есть два варианта реализации. Первый. Предпочтительный. Реально все пойнтера виртуальной машины таскают с собой пойнтер на интерфейс, по которому и происходит обращение к vmt. Это позволит реализовать cast с заменой в пойнтере интерфейса на любой нужный. Дальше вызов по vmt[ordinal интерфейса]. Второй вариант совсем тупой — invokedynamic. Но он пока без полиморфизма. Что, впрочем, тоже решается легко — передавать сигнатуру вместо имени метода.