Necromancer13 Вообще-то содержательная беседа идёт почти исключительно о Линухе и альтернативных способах реализации кой-чего (что маленькие дети всё равно не поймут :-P ) в ядре системы
SII пока асм кодер строфает код лучше компиля, так оно и будет, но сама жизнь требует алгосов решения этой задачи в авторежиме, ибо сложность систем растёт и оптимайзить код "ручками" станет практически невозможным - слишком большой объём работы. так что переходу на чистый яву мешает отсутствие нормального компиля, но это дело времени. угу. а вот оптимизма твоего разделить не могу: А. не всякая задача может быть распараллелена; Б. не всякая задача имеет приемлемое решение распараллеливания.
UbIvItS Бесполезняк. Сейчас SII или проигнорирует, или сделает очень далекий заход, оперируя древними данными (ДОС вспомнит например), или объяснит, что это должен быть Паскаль
В "абсолютном" смысле эта задача решена, вероятно, не будет: чтобы писать программы на уровне человека, надо понимать, что делает программа в целом, т.е. обладать полноценным интеллектом. Кстати, если это всё же будет, то человек становится ненужным: машина сама сможет себя программировать Кроме того, перейти на "чистый ЯВУ" можно только в том случае, если железо станет совершенно стандартным. Грубо говоря, если железо напрямую будет реализовывать то, что сейчас реализует жабовская или дотнетовская ВМ. А пока этого нет -- ассемблер будет абсолютно необходим. А где Вы увидели мой оптимизм? Я лишь сказал, что разработка многопоточных (воспользуемся современным термином) программ -- дело отнюдь не новое, и какие там проблемы имеются, хорошо известно. Ну а что не всё можно распараллелить -- это и ежу понятно.
SII Не ожидал Предрекают появление новых процов, которые напрямую будут обрабатывать команды p- кода. Технически это возможно. Что на это можно сказать?
SII допустим есть Linux процесс вызывает pause(), переходит в режим ядра, изменяет свое состояние на TASK_INTERRUPTIBLE и переходит в состояние ожидания посредством schedule() при выполнении нужного условия (наличие сигнала) некоторый другой процесс, находящийся в режиме ядра, возвращает исходный процесс в активную очередь выполнения на каком-либо свободном процессоре вот тут самое интересное переключение контекста на этот процесс происходит не сразу из-за различных ограничений (приоритет, квант времени текущего процесса и т. д) после получения управления, процесс выполняет определенные завершающие действия, которые в вашем случае должна выполнить асинхронная функция но асинхронная функция выполняется сразу после детекта события, но перед переключением контекста вот тут может быть задержка, потому как момент переключения недетерминирован UbIvItS ну и какие built-in функции должен реализовывать компилятор? лично я подход, предложенный SII в книжках не встречал хотя, может плохо читал
vito мда..... упёртый чел, зато мне весело не надо путать хард оптимайз кода (чисто математическая задача) и генерация алгоса (Интеллектуальная задача, хотя математика в ней превалирует, но присутствует и интуитивная часть, что, собственно, и делает её интеллектуальной). забавно) - ты никак не хочешь разделять элементарные асм команды проца и его функционал - неужели это для тебя одно и тоже )? rei3er хорошая шутка а-ля вопрос
А собственно какие проблемы? Например в 16-bit TurboPascal, существовал машинно-зависимый interrupt[xx] который отсутствует в 32-битных версиях. Тем не менее OOП возможности языка вполне позволяют его "сэмулировать" его 32-битный аналог... Код (Text): type Tint_table = array [0..255] of IdtDescr; Tinterrupt = class private function GetVect (index:byte):pointer; procedure SetVect (index:byte; value:pointer); public T : ^Tint_table; (* Адрес таблицы прерываний *) property IntNum[index:byte]:pointer read GetVect write SetVect;default; end; procedure Tinterrupt.SetVect(index:byte; value:pointer); begin T[index].BaseLo := cardinal(value); T[index].BaseHi := cardinal(value) shr 16; (* T[index].Selector := 8; *) (* T[index].Attrib := $8E {dpl0, interrupt_gate_type}; *) end; function Tinterrupt.GetVect(index:byte):pointer; begin Result := pointer (T[index].BaseLo + T[index].BaseHi shl 16); end; В результате чего юзаем обьектную переменную, довольно просто: interrupt[num] := interrupt[num]; Аналогично "эмулируеться" и port[xxx]
rei3er Вообще-то асинхронная функция отнюдь не сразу выполняет действия после обнаружения события -- она их выполняет тогда, когда получит управление А чтобы получить его, она должна быть поставлена в очередь других асинхронных обработчиков -- их же может быть несколько. И тут легко ввести разграничение: отдельно складывать общесистемные обработчики (которые не зависят от контекста потока; собственно, они и так всегда складываются отдельно), а отдельно -- обработчики для конкретных потоков. Последние получают управление в том случае, когда планировщик производит переключение на контекст потока. В данном случае получается так. Поток перешёл в ожидание некоего события и был снят планировщиком с процессора. Через некоторое время произошло ожидаемое событие, которое требует пробуждения потока, однако перед возвращением ему управления надо выполнить некоторый дополнительный код. В связи с этим поток выводится из ожидания, однако ему в очередь асинхронных обработчиков вписывается нужный обработчик. Когда планировщик доберётся до этого потока (ведь он уже не ожидает), он загрузит его контекст, а потом обнаружит, что в очереди имеется асинхронный обработчик. Осознав сей факт, планировщик не возвратит управление потоку, а вызовет сначала этот обработчик, который сделает свои чёрные дела, после которых поток, наконец-то, сможет быть возобновлён (если, конечно, асинхронный обработчик его по каким-то причинам не прибьёт или не отправит опять в ожидание). Этот подход в близком к изложенному мной виде использовался в RSX-11M и VAX/VMS (в этих машинах были, правда, кой-какие "фишки", связанные с учётом их архитектурных особенностей -- которые я в своём изложении, естественно, опустил, не поменяв сути самого метода). Потенциально он "заложен" и в Винду NT-2000-XP-2003 (вопрос в том, насколько хорошо он там реализован: обработка прерываний там является "расширенной версией" схемы, применяемой в VAX/VMS, причём, судя по тем описаниям, что я видел, "хотели как лучше, а получилось как всегда", т.е. перемудрили, сделали слишком сложной и менее эффективной). Что ж касается литературы, то не знаю, где он описан. Я-то опирался на документацию (и исходники) RSX-11M, а также на документацию к VAX/VMS (её исходников у меня, увы, нет, но надеюсь, что когда-нибудь где-нибудь найду). UbIvItS А я не путаю. Компилятор, выполняя оптимизацию, не располагает всей информацией о задаче. Например, он не знает, каков диапазон входных данных, а значит, не может провести некоторую оптимизацию, основанную на таком знании. Он не знает, какие циклы выполняются много раз, а какие -- мало. Он не знает вероятность ветвления в том или ином случае. Конечно, всё это можно дополнительно описывать ручками в программе, но во что тогда превратится её исходный код? И как его тогда можно будет читать? Функционал процессора складывается как раз из его элементарных команд. И присутствуют там не только команды сложения-вычитания и им подобные, которые по сути одинаковы на всех вычислительных машинах, работающих в двоичном коде и использующих для представления отрицательных чисел дополнительный код (а все известные мне машины, существующие на сегодняшний день, именно такие), но и команды, специфические для конкретной платформы, аналогов которым на других платформах попросту нет.
bugaga ты всерьез полагаешь, что это в этом заключается вся работа с прерываниями? и сигнатуры функций можно с IA-32 экстраполировать на все архитектуры? UbIvItS по существу, пожалуйста SII вообще говоря, планировщик не должен заниматься поиском и вызовом зарегистрированных потоком асинхронных функций это не его задача вот еще, только сейчас об этом подумал чем у вас представлен планировщик? потоком ядра? а как идет его вызов? (аналог schedule() в Linux) если это поток ядра, то должно идти переключение контекста на него т. е получается, чтобы переключить контекст, нужно переключить контекст (для вызова планировщика) рекурсия...
rei3er Отчасти Вы правы, но до конца согласиться не могу. В самом деле, планировщик выбирает, какой поток должен занять процессор, а заодно осуществляет переключение контекстов. Почему же он не может при этом одновременно переключиться на "подконтекст" асинхронного обработчика? Это реализуется очень просто, никакого запутывания логики работы не происходит. Нет, планировщик -- это отдельная подпрограмма, вызываемая подпрограммой завершения прерывания, когда последняя обнаружит, что не осталось ни одного необслуженного прерывания, но установлен флаг вызова планировщика (он устанавливается, если какой-либо обработчик прерывания пришёл к выводу, что текущий поток должен быть снят с процессора). Технически его можно рассматривать как самый отложенный из отложенных обработчиков прерываний (поскольку он вызывается после выполнения всех имеющихся отложенных обработчиков). Так что никакой рекурсии
reiser Ну вроде как всего хватает поскольку задача тривиальна - посадить на вектор указатель обработчика.. Класс Tinterrupt доводилось использовать в нулевом кольце винды, чисто для перестраховки от BSOD-a, на случай возникновения исключений. лично мне класть с прибором, на "все архитектуры", кроме IA32... C ней бы как нибудь разобраться..
SII угу, эта сакральная инфа жифёт в астрале, а сам код проги хз нахЪ он нужен) дастиш фантастиш, это выше всяких похвал) ======>> для каждого проца формируется персональная либа с одним и тем же набором фунок - эти либы являют собой один и тот же функционал. помнишь перегруженные функи в твоём "любимом" си, а может их тоже соорудить невозможно - ведь они получают разные входные данные и, стало быть, состоят из разных эл. операций)? rei3er ладно, рассмотрим, например, мак и пк ==> вопросы: там и там есть сис. таймер?? там и там есть переф. устройства?? --------- итого вопрос - а какие прерывания надо всунуть в яву)??
UbIvItS Во-первых, не в моём любимом Си, а в моём ещё более любимом Си++. А во-вторых, как Вы предлагаете реализовать функции для того, чего у процессора нет напрочь? Или что совершенно не так реализовано, как на других архитектурах?
SII Для этого и создавались стандарты. Конечно идеалы не сбылись, но портирование на разные платформы, задача относительно легкая, если сравнивать, с написанием с 0. А то что не реализовано на конкретной железяке, должно учитываться компилем под нее, при условии соблюдения стандартов (и соответственно оптимизироваться). Но впрочем это уже бывает эмуляция, и в зависимости от задачи, код в большей или меньшей степени доводится. Речь не только о ядре ОС, хотя подобный подход может быть применен и в данном случае.
SII ранее я уже ответил на этот вопрос: равный функционал а при чём здесь это(???): если у проца есть, к примеру, возможность в/в - значит её можно реализовать на его асме ввиде функи; засунуть её в либу, а на яву эта функа имеет униф. форму - так в чём проблем???
к примеру, CPU имеет возможность инвалидации строки кэша L1/L2 CLFLUSH как реализовать в виде built-in функции эту инструкцию для других архитектур, которые, допустим, не поддерживают работу со строками кэша? поставить пустую заглушку? тогда семантика использования (цель) нарушится или те же барьерные инструкции LFENCE/MFENCE/SFENCE они тесно связаны с конкретной архитектурой, а точнее даже с конкретным семейством процессоров в рамках конкретной архитектуры опять ставить заглушки? вообщем, имхо, вы говорите чушь
а смысл? переносимость на уровне исходников теряется т. е теряется весь смысл использования ЯВУ нельзя создать унифицированную сигнатуру с унифицированным набором параметров для всех архитектур
SII все, конечно, хорошо, но возникает закономерный вопрос: а для чего, собственно, все эти трудности? не проще ли выделить каждому потоку 4K ядерного стека? разделять не ядерные и пользовательские потоки, а всего лишь их контекст архитектура упрощается, что немаловажно для современных больших ОС простота - большая гибкость, большая гибкость - большая масштабируемость и т. д