На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru


Страницы: (21) « Первая ... 14 15 [16] 17 18 ...  20 21  ( Перейти к последнему сообщению )  
> Разработка концептуально новой ОС
    Цитата rcz, 29.09.03, 16:52:27

    1)Делать ядро без страничной адресации ??? Или под "трансляцией адресов" понимается что-то другое ?

    Нет. Страничную адресацию в ядре стоит включить. Не выключать/включать же ее при каждом переключении задач. Тем более на ее поддержку в ядре не будет издержек.

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

    Цитата
    Только другой вопрос - все ли можно будет выкидывать в своп файл? Будет диапазон неподкачиваемой памяти.

    Очевидно, весь код ядра и важнейшие данные должны быть резидентны.
    Кучу ядра, скорее всего, стоит сделать подкачиваемой - иначе может оказаться, что больше 1000 процессов запустить одновременно не удастся.

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

    Цитата
    2) что значит "получим лишнее переключение задач - внутри ядра. То есть все syscall-ы, требующие управления памятью, повлекут не одно, а два переключения задач. " ? Из-за чего ?

    Согласен.. не повлекут :-[
    Цитата
    Да. только микроядро будет непрерывным куском. А делее все модули будет динамическими.. Но в физической памяти располагаться после ядра.

    Что тут названо микроядром? Ведь изначально все ядро планировалось "микро", а все остальное - обычные процессы (пусть даже некоторые - по многочисленным настояниям  ;) - в привилегированном режиме).

    Цитата
    (Сюда не кидали, потому что это имеет малое отношение к концепции и архитектуре ОС)

    Может, не сюда - но куда-то, по-хорошему, надо бы скидывать все, что есть.
    Может, прямо сейчас сделать какой-нибудь html-сайт?
      Память системы (виртуальная).
      Цитата

      0x00000000  -  0x00001000 ---- Одна страница не отображается. Для ошибки нулевого указателя.
      0x00001000  -  0x80000000 ---- Ring 3  Приложения    // селектор имеет базу 0. размер 0x80000000
      из них  можно последних 0x20000000   для чего-то вроде DLL.
      0x80000000 - 0xc0000000 ---- Ring 1  для драйверов. // селектор имеет базу 0. размер 0xc0000000
      0xc0000000 - 0xffffffff ---- Ring 0 // селектор имеет базу 0. размер 0xffffffff

      1)Т.е. тут получается, что приложения из менее привилегированного уровня не могкт даже видеть пространство с долее привилегированного уровня.
      2) В Ring1 помещаются толко драйвера из свопируемой памяти. (где страничные нарушеня допустимы).  Лучше сделать, что каждый драйвер работает в своем адресном пространстве. Критически важные драйвера (HDD)  - отвесающие за своп лучше в несвопируюмую память.

      Память ядра.


      Цитата

                       Физический адрес<----> Виртуальный
      Неинициализированные данные ядра (т.е. Инициализируются уже самим ядром)

      Каталог страниц   0x400000            0xc0000000
      Таблицы страниц  -----                  0xc0001000  //4 мб

      GDT                     0x401000            0xc0401000
      IDT                      0x401200            0xc0401200

      Первая физическая страница стека(ее надо инициализировать. Чтоб при изменении ядром каталогов страниц не было проблем с переносом стека)
                               0x402000             0xfffff000
      Reserved               -----                  0xc0402000

      Инициализированные данные. Т.е. Эти данные копирует лоадер. Считывает сюда.
      kernel.bin.             0x403000             0xc0403000


      Инициализированные ядром данные.
      далее Пул физической памяти. -
                  Phys_Kernel_addr+sizeof_Kernel          Virt_Kernel_addr+sizeof_Kernel
      (Отдельный пул памяти <0x400000 для DMA и других системных назначений.)

      Хип ядра.               ---------             Pool_Addr+Pool_Size

      Стек ядра 0xffffffff  - может не лучшее место, но не могу придумать куда его еще кидать, чтоб ничего не портил.  растет вниз


      Каталоги страниц выделяются из пула свобродной физической памяти. "Мапятся" в виртуальное адресное простарнство 0xc0001000 - 0xc0401000. Причем все последовательно (по возрастанию виртуальных адресов).

      Пул физической памяти можно для начала сделать как
      ExpandedWrap disabled
        <br>union phys_pages{<br>      struct{<br>            word nextIndex,prevIndex; //список<br>      }<br>      dword virtMapped; // Определяет некий объект, отвечающий за каждое выдеоение памяти (виртуальный адрес, куда отображено; количество ссылок; флаги...).<br>}<br>phys_pages pool[SizeOfPool- вычисляется по количеству физической памяти];<br>


      Весь пул - массив этих union.  nextIndex,prevIndex - индексы в нем. Он определяет физические страницы по адресам (физическим) phys_kernel+sizeof_kernel+size_of_pool.
      Виртуальный адрес его соответственно virt_kernel+sizeof_kernel+size_of_pool.
      Т.е. индекс в нем соответствует индексу физической страницы в этом диапазоне.

      После можно это переделать. Сделать выделение не только страницами, но и 2-мя 4-мя 8-мью и т.д страницами. Сделать несколько пулов.

      З.Ы. здоровая критика, предложения приветствуются.
      Сообщение отредактировано: rcz -
        Критиковать слишком много  :), поэтому сначала предложения.

        Карта физической памяти.
        0x0 - 0x0000FFFF  - стек ядра (код гарантирует непереполнение)
        0x00010000 - X-1  - таблицы дескрипторов (глобальная и прерываний).
        X               - Y-1  - код ядра
        Y               - Z-1  - таблица системных описателей физических страниц.
        Z               - max -  heap ядра и память приложений (перемешаны).

        Z зависит от размера физической памяти и определяется при загрузке.

        Карта виртуальной памяти ядра.
        Отличается от физической только последней строкой:
        ...........................................
        Z    - max_virtual  - heap и резервные адреса ядра.

        Карта виртуальной памяти приложений и драйверов.
        0x0 - max_virtual  - доступные адреса ("пустые").
        Сообщение отредактировано: nvm -
          Я отправил в начало каталоги страниц, т.к. при загрузки ядра точно неизвестен его размер (в образе ядра например не хранится секция неинициализированных данных). Поэтому лучше в начало. Просто удобно это иметь по фиксированному адресу каталоги и таблицы страниц


          I)
          Цитата

          Карта физической памяти.
          0x0 - 0x0000FFFF  - стек ядра (код гарантирует непереполнение)

          В 0 нельзя отправлять ядро по нескольким причинам
          1) там БИОС. Он может еще понадобиться
          2) DMA не может находиться далеко.

          II)
          Цитата
          Y               - Z-1  - таблица системных описателей физических страниц.

          Это я назвал пулом. Структуру привел. Хотя не продумал выделение физической памяти для объектов, описывающих выделенные страницы физичексой памяти.
          А для каждой страницы хранить такой объект неразумно. Их надо ведь объединять.

          (Предположение - выделение из Хипа ядра , а его(или только его часть) сделать фиксированным).

          III)
          Цитата
          Z               - max -  heap ядра и память приложений (перемешаны).

          Физически перемешаны.

          Хип ядра работает следующим образом:
          Выделять можно меньше страницы.
          Это список.
          Резервируется место - выделяются из пула физические страницы (если хип закончился). Можно сделать его нерасширяемым и выделять только при инициализации. Эти страницы добавляются ("мапятся") в пространство хипа. Инициализируется(обновляется) список хипа. Далее из этого списка выделяется память.

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

          Цитата
          Карта виртуальной памяти приложений и драйверов.
          0x0 - max_virtual  - доступные адреса ("пустые").

          Только этого не понял. 1) Не будут же приложения с ядром находиться в одной куче виртуальных адресов. 2) а зачем вводить max_virtual. Виртуальное пространство можно не ограничивать.

          Цитата
          Критиковать слишком много  , поэтому сначала предложения.

          Хотя привел почти то же самое. Про каталоги и таблицы страниц забыл. Без них страничной адресации не будет.
          Сообщение отредактировано: rcz -
            Цитата rcz, 30.09.03, 15:27:31
            Я отправил в начало каталоги страниц, т.к. при загрузки ядра точно неизвестен его размер (в образе ядра например не хранится секция неинициализированных данных). Поэтому лучше в начало. Просто удобно это иметь по фиксированному адресу каталоги и таблицы страниц

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

            Цитата
            В 0 нельзя отправлять ядро по нескольким причинам
            1) там БИОС. Он может еще понадобиться

            Биос ведь сверху?? А в 0, как я помню, только его вектора прерываний. От них можно чуть отступить - не проблема.

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

            Цитата
            2) DMA не может находиться далеко.

            Это проблема. Если ядро услать высоко, то придется писать еще один загрузчик - для защищенного режима. А если все поместить в 640 кб, то можно загрузить все ядро функциями Биос.
            Сколько конкретно нужно под DMA?

            Цитата

            Это я назвал пулом. Структуру привел. Хотя не продумал выделение физической памяти для объектов, описывающих выделенные страницы физичексой памяти.
            А для каждой страницы хранить такой объект неразумно. Их надо ведь объединять.

            Честно говоря, не понял идеи. Но, навскидку, кажется, что структура сложная и негибкая.

            У меня другое предложение: хранить простой массив указателей, где для каждой физической страницы стоит ссылка на дескриптор объекта, которому она выделена, или NULL, если страница свободна. Такой массив займет ровно 0.1\% памяти.
            Каталоги страниц объекта (процесса) хранить в дескрипторе объекта, который находится в куче ядра.

            Цитата
            Физически перемешаны.

            Разумеется. Так как виртуально - ...они вообще в разных адресных пространствах! 8)

            Цитата

            Хип ядра работает следующим образом:
            .......

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

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

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

            Цитата
            Только этого не понял. 1) Не будут же приложения с ядром находиться в одной куче виртуальных адресов.

            У каждого приложения и драйвера - свое "чистое" виртуальное пространство от 0x0 до 0xFFFFFFFF, в котором нет ничего, кроме секций, выделенных этому процессу.

            Цитата
            2) а зачем вводить max_virtual. Виртуальное пространство можно не ограничивать.

            Реально оно ограничено размером файла подкачки.. или места на диске.
            Но для приложений ограничение на используемый диапазон адресов действительно нужно снять - дать все 4Гб (вдруг программа захочет загрузиться не спошным куском).

            Цитата
            Хотя привел почти то же самое.

            Думаю, совсем не то же.
            1) У вас сказано, что приложения не видят ядро. Это само собой, но у меня они не видят вообще ничего, кроме себя. Кстати ядро тоже не видит страницы приложений, но, естественно, имеет возможность по-необходимости их "подцеплять" на выделенный буфер.
            2) У вас не ясно, где хранятся каталоги страниц для процессов. У каждого процесса должен быть свой каталог разделов и страниц, пополняемый по мере выделения памяти - хранится он в дескрипторе процесса (это не просто структура, а дерево структур) в куче ядра.
            3) Уже в исходной спецификации я предлагал революционную  8) ;D идею, что при выделении памяти процессу не ядро выбирает виртуальный адрес, по которому будет видна эта память - а сам процесс передает его как входной параметр!
              Поправка к спецификации и заодно, уточнение про процессы и потоки.

              Изначально предлагалось, чтобы при посылке сообщения, создающего новый поток, передавался стек для этого потока.
              Это практически нереализуемо: так как стек передан из другого процесса, то создаваемый поток должен его сначала отобразить в свое адресное пространство, а для этого нужно вызвать syscall, для чего нужно уже иметь стек.
              Да это и некрасиво: стеки потоков будут засорять адресное пространство процесса.

              Поток пользуется адресным пространством (картой памяти) процесса, но стек ему нужен свой (и контекст регистров).

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

              Такая архитектура усложняет структуры данных ядра, но представляется достаточно стройной для API.
                [quote]..Только не список.. Надо бы что-нибудь хитрое придумать - против фрагментации. Например, сгруппировать по размерам.
                И необходимо heap ядра делать все же расширяемым - в нем ведь дескрипторы для всех хэндлов, каталоги страниц (а это могут быть мегабайты).[/quote]
                Естественно будет группироваться по размерам. Но при разбиении их получится список. И список ведь расширяемый.

                [quote]Загрузка приложений не имеет специфики: память выделяется совершенно обычными запросами (ядро не занимается загрузкой приложений - это делают другие приложения, которые сначала сами запрашивают нужное количество памяти, затем пишут в нее код, потом просят систему соорудить из созданных секций процесс, после чего при желании убирают эти секции из своего адресного пространства).
                Heap приложений кратен странице, и с точки зрения ядра - это просто секция.[/quote]
                [quote]3) Уже в исходной спецификации я предлагал революционную    идею, что при выделении памяти процессу не ядро выбирает виртуальный адрес, по которому будет видна эта память - а сам процесс передает его как входной параметр![/quote]
                Правильно. Выбирает не ядро, а загрузчик исполняемых файлов. Информация о том, куда грузить, может находиться в заголовке файла. (нереволюционная идея. А сам процес, до того как получит управление, чтобы определить куда ему надо, уже будет куда-то смаппирован)

                [quote]Думаю, совсем не то же.
                1) У вас сказано, что приложения не видят ядро. Это само собой, но у меня они не видят вообще ничего, кроме себя. Кстати ядро тоже не видит страницы приложений, но, естественно, имеет возможность по-необходимости их "подцеплять" на выделенный буфер.[quote]
                Ядро должно их видеть. Хотя бы передача параметров в syscall без этого невозможна.

                [quote]2) У вас не ясно, где хранятся каталоги страниц для процессов. У каждого процесса должен быть свой каталог разделов и страниц, пополняемый по мере выделения памяти - хранится он в дескрипторе процесса (это не просто структура, а дерево структур) в куче ядра. [/quote]
                До процессов я не дошел. Но, вспоминая структуру задачи TSS в x86. Там есть поле cr3, которое как раз отвечает за каталог страниц. Он хранит физический адрес. Виртуальный - можно мапить при обработке каталога, или всегда при переключении задач на фиксированный виртуальный адрес.

                [quote]
                Честно говоря, не понял идеи. Но, навскидку, кажется, что структура сложная и негибкая.

                У меня другое предложение: хранить простой массив указателей, где для каждой физической страницы стоит ссылка на дескриптор объекта, которому она выделена, или NULL, если страница свободна. Такой массив займет ровно 0.1\% памяти. [/quote]

                Была идея сделать примерно так.

                ExpandedWrap disabled
                  <br>union phys_pages{ <br>      struct{ <br>            word nextIndex,prevIndex; //список <br>      } <br>      section * sect; // Определяет некий объект, отвечающий за каждое выделение памяти (виртуальный адрес, куда отображено; количество ссылок; флаги...). <br>};<br>phys_pages pool[pool_size]<br><br><br>struct section{<br>     dword flags;<br>     dword *phys_pages; //размер = (virt_end-virt_start)/PAGE_SIZE. Округлен в большую сторону. <br>     dword virt_start;<br>     dword virt_end;<br>     dword ref_count; //для shared memory<br> };<br>//секция - непрерывная область виртуальной памяти. начинается с virt_start. Все эти страницы имеют общие флаги. phys_pages - массив индексов в пуле физической памяти (phys_pages pool[pool_size]). индекс=0 - физическая страница не выделялася;индекc < 0 - Она в свопе, тогда это поле уже по другому интерпретируется<br><br>//а в процессе<br>struct process{<br>   ...<br>   list<thread>m_threads;<br>  ...<br>  list <section>m_sections;<br>,.<br>};<br>//выделение памяти получится примерно такой.<br>virtual_alloc(start,size);// - создается секция.<br><br>Далее при необходимости выделяются и мапятся физические страницы. (добавляются в массив индексов и в каталог страниц).<br><br>virtual_free(start); //unmap и освобождает секцию, где virt_start=start. Уменьшает ref_count. Если стал 0 - освобождает все занятые физические страницы.<br>


                [quote]Решение предлагается следующее.
                Ввести осовый вид секции - секция стека, со свойствами:
                - уникальность в пределах процесса,
                - отсутствие пересечений с другими секциями, как по физическим, так и виртуальным адресам,
                - клоновость: для каждого потока из задачи делается собственный клон секции стека, на тех же виртуальных адресах, но со своим отображением в физическую память.
                Все клоны имеют один и тот же хэндл.  

                Такая архитектура усложняет структуры данных ядра, но представляется достаточно стройной для API. [/quote]
                В таком случае и ввести свой хип. И придем к тому, что структура потока= структуре процеса, только секции кода и данных имеют одни и те же. От чего и отказывались.
                Сообщение отредактировано: rcz -
                  Цитата rcz, 01.10.03, 13:01:48

                  Естественно будет группироваться по размерам. Но при разбиении их получится список. И список ведь расширяемый.

                  Один вариант такой.
                  Правда в этом случае будет нереально память, однажды выделенную ядру, возвратить в пул свободных страниц.
                  Есть еще идея, не противоречащая списку, а являющаяся надстройкой над ним: сделать не сплошную одну кучу, а разбить ее на блоки, в каждом из которых оптимизировать выделение памяти под специфику блока. При этом указатели будут уже не адресами, а индексами (блока и адреса в нем). Это позволит освобождать страницы, а также при необходимости двигать данные в памяти.

                  Цитата

                  Правильно. Выбирает не ядро, а загрузчик исполняемых файлов. Информация о том, куда грузить, может находиться в заголовке файла. (нереволюционная идея.

                  Загрузчик - частный случай. Создавать процессы и загружать в них код может любое приложение.
                  Причем одних только "штатных" загрузчиков понадобится минимум 4: для DOS, Unix, Windows, и собственного формата.

                  ..Ну как не революционная: обычно malloc возвращает адрес, а у тут - адрес (виртуальная структура сегмента) ей передается на входе.

                  Цитата
                  А сам процес, до того как получит управление, чтобы определить куда ему надо, уже будет куда-то смаппирован)

                  Не весь: кучу и любые дополнительные секции (в т.ч. разделяемые) он мапит потом сам.

                  Цитата
                  Ядро должно их видеть. Хотя бы передача параметров в syscall без этого невозможна.

                  Я же сказал, что ядро всегда может отобразить любую страницу приложения на фиксированный адрес в своем пространстве - оттуда и читать параметры.
                  А постоянно видеть всю память приложений ему, к счастью, не надо.

                  Цитата
                  До процессов я не дошел. Но, вспоминая структуру задачи TSS в x86. Там есть поле cr3, которое как раз отвечает за каталог страниц. Он хранит физический адрес. Виртуальный - можно мапить при обработке каталога, или всегда при переключении задач на фиксированный виртуальный адрес.

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

                  Цитата
                  Была идея сделать примерно так.
                  union phys_pages{
                       struct{
                             word nextIndex,prevIndex; //список
                       }
                       section * sect;
                  };

                  union - не годится. Нужно как-то только по содержимому phys_pages определять, свободна ли эта страница. Кроме того, в word диапазон индексов в общем случае не поместится.
                  Лучше сделать на идее, как в таблице IDODs в суперблоке FS Unix.
                  Завести специальную секцию свободных страниц, причем не помещать туда все свободные страницы, а только часть. А при исчерпании "запаса" просматривать все phys_pages и пополнять секцию.

                  Цитата
                    list<....

                  Все-таки, почему list, если жизненно необходим vector ?!
                  Все эти структуры адресуются через хэндл, то есть индекс, поэтому нужен массив.

                  Цитата

                  //выделение памяти получится примерно такой.
                  virtual_alloc(start,size);// - создается секция.

                  Так и было.
                  Только есть еще важный второй вариант: когда мапится секция, полученная от другого процесса. Это тоже разновидность alloc..
                  А еще полезна возможность расширения уже выделенной секции, хотя это детали.

                  Цитата
                  virtual_free(start); //unmap и освобождает секцию, где virt_start=start. Уменьшает ref_count. Если стал 0 - освобождает все занятые физические страницы.

                  ОК, только: virtual_free(handle);

                  Цитата
                  В таком случае и ввести свой хип. И придем к тому, что структура потока= структуре процеса, только секции кода и данных имеют одни и те же. От чего и отказывались.

                  Ну нет! Heap - это всего лишь разновидность секции данных (причем об отличии знает только само приложение), прием хипов может быть сколько угодно, как и любых секций, кроме стека.

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

                  При создании потока ему создается "чистый" стек, в котором содержатся только параметры сообщения.
                  Сообщение отредактировано: nvm -
                    Начата работа над сайтом системы:
                    http://www.ios.ru/~nvm/index.html
                      Цитата nvm, 30.09.03, 19:19:33
                      3) Уже в исходной спецификации я предлагал революционную  8) ;D идею, что при выделении памяти процессу не ядро выбирает виртуальный адрес, по которому будет видна эта память - а сам процесс передает его как входной параметр!
                      Хых... когда не ведаешь, что было сделано задолго до тебя, то и впрямь чувсвуешь себя первооткрываетелем :D

                      Цитата nvm, 01.10.03, 18:49:31

                      ..Ну как не революционная: обычно malloc возвращает адрес, а у тут - адрес (виртуальная структура сегмента) ей передается на входе.
                      Ну так malloc() к ОС имеет весьма отдалённое отношение. В конечном счёте, вызывается syscall, которому передаётся адрес и размер области, куда мэпится выделенная память.

                      Определение секций на уровне ядра совсем ни к чему. Никаких структур и дескрипторов не нужно. Ядро работает только с Virtual Memory Areas в юзерном пр-ве процесса. В этом случае, секция стека - всего лишь отдельная VMA с правами страниц на READ/WRITE, в которую спроецирована реальная память, причём те страницы, в которых ещё не было записи данных, реально указывают на единственную в системе физическую страницу, затёртую нулями. Значит, 4Мб стек может реально занимать очень мало памяти, и для секции стека не нужно изобретать ещё одну сущность, поскольку это такая же секция, что и код и данные, олько с разными правами доступа.

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

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

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

                      Делая так, вы таким образом выкидываете из уровня ядра ненужный хлам на уровень приложения.

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

                      Даже когда много модулей работает в режиме ядра, само ядро может оставаться микро- или наноядром.
                        1)Объекты (процессы, драйвера) содержат интерфейсы-методы(непосредственно функции обработки).

                        Механизм обработки сообщений. Как происходит?
                        (Передача их еще понятна. Ядро по ключу находит процесс, отвечающий за интерфейс, и адрес обработчика).

                        Цитата
                        Для вас такая схема неудобна, поскольку ядро само создаёт тред для обработки пришедшего в процесс сообщения. И это не единственное осложнение, которое у вас появится, если вы будете и дальше отказываться от модели пулов тредов, которая на самом деле, проще, красивее и эффективнее в реализации, да к тому же, м.б. совершенно прозрачна для прикладного программиста - достаточно сделать ф-цию GetMessage() по проинципу fork(), (однако, она будет не syscallом, а библиотечной ф-цией).


                        Интерфейс - остановленный тред. При получении сообщения, он активизируется. (параметры - данные ключа). Можно сделать, что именно при объевлении интерфейса создается контекст треда (точнее TSS) и он не изменяется (для всех вызвов одинаков, т.е. потом при активизации потока он дублируется).

                        Получается такой механизм

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

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

                        2) Хэндлы и указатели. и
                        Цитата

                        >  list<....  
                        Все-таки, почему list, если жизненно необходим vector ?!
                        Все эти структуры адресуются через хэндл, то есть индекс, поэтому нужен массив.

                        list - удобней добавлять, удалять и т.п. Без лишних выделений, перемещений. Удобней искать (двунаправленный список можно преобразовать в дерево поиска).
                        vector - тоже можно. Но если разервировать память с запасом - часто лишний расход памяти. Меньше зарезервировать памяти - чаще все придется переносить. Использование того или иного в конкретном случае будем рассматривать отдельно и желательно на готовом ядре(измерять производжительность будем).

                        И для ядра часто(не всегда) удобней работать не хэндлами, а указателями. Т.е. оно сначало получает указатель объекта, а потом с ним работает. Так должно быть с секциями памяти.

                          Цитата Vilmor, 02.10.03, 10:40:56

                          Хых... когда не ведаешь, что было сделано задолго до тебя, то и впрямь чувсвуешь себя первооткрываетелем :D

                          Это ведь было в шутку - насчет революционности. В наше время новое придумать почти нереально.. но все равно полезнее самому дойти до идеи, чем взять ее готовой...

                          Цитата

                          Определение секций на уровне ядра совсем ни к чему. Никаких структур и дескрипторов не нужно. Ядро работает только с Virtual Memory Areas в юзерном пр-ве процесса.

                          Чем Ваш VMA отличается от секций? Может, опишете существо?

                          Здесь секция - универсальная абстракция для области памяти.
                          В x86 секция по-хорошему должна поддерживать в полном объеме возможности сегментов - а на других платформах позволять без сегментов обходиться.
                          Секция по смыслу похожа на сегмент (и призвана его эмулировать на платформах, где он не доступен). А сегмент - сущность процессора, то есть самого низкого уровня, так кому, как не ядру ее поддерживать?!

                          Цитата
                          В этом случае, секция стека - всего лишь отдельная VMA с правами страниц на READ/WRITE, ... и для секции стека не нужно изобретать ещё одну сущность, поскольку это такая же секция, что и код и данные, олько с разными правами доступа.

                          В идеале, стек - это объект с интерфейсрм всего их двух функций: push и pop. И ему вообще не нужно адресное пространство. То, что в современных архитектурах ему приходится выделять адреса - это технические издержки.
                          Это аргумент в пользу выделения стека в отдельную сущность.
                          Еще особенность - стек логически привязан к потоку, в то время как остальные секции - к задаче.

                          Цитата
                          К тому же, если у процесса несколько тредов, то тогда ОС безразлично, как программа выделяет память для стеков - в одной секции или в нескольких. Программа, создавая тред, сама выделяет память для его стека.

                          Изначально я так и предполагал.
                          Но проблема в том, что тред может быть создан извне другим процессом, который не может смонтировать стек в данном процессе (см. пост 230).
                          Потом, поддержка потоков - это все-таки ведение ядра, и нехорошо загружать этими низкоуровневыми проблемами приложения.

                          Насчет "клонированных стеков" в одном сегменте - эта идея, думаю, на самом деле совершенно новая и нигде не опробованная. Поэтому у меня самого нет в ней полной уверенности, но предварительно выглядит привлекательной.

                          Цитата
                          И это не единственное осложнение, которое у вас появится, если вы будете и дальше отказываться от модели пулов тредов, которая на самом деле, проще, красивее и эффективнее в реализации,

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

                          Цитата
                          Делая так, вы таким образом выкидываете из уровня ядра ненужный хлам на уровень приложения.

                          И заваливаем этим хламом приложение..

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

                          И что?.. Разве кто-то предлагал что-либо, вызывающее зависимость ядра от модулей??
                          Есть одна зависимость: для реализации подкачки ядро вынуждено обращаться к драйверу диска - но это исключение неизбежно и единственно.

                          Но микроядро - не означает простое. У него обязан быть простым интерфейс (содержать малое число сущностей и методов). А реализация может быть очень нетривиальной.
                          Я бы ожидал размер исходников ядра около 50кб, то есть где-нибудь 30кб после компиляции - но это был бы очень сложный код. Но для ОС всегда стоит пойти на сложность реализации ради простоты использования.
                            Цитата rcz, 02.10.03, 11:49:26
                            Механизм обработки сообщений. Как происходит?
                            (Передача их еще понятна. Ядро по ключу находит процесс, отвечающий за интерфейс, и адрес обработчика).

                            Механизм принципиально отличается для разных типов сообщений.
                            1) Post/SendMessage.
                            Сообщение ставится в очередь, где ждет вызова GetMessage().
                            Если очередь пуста, то вызов GetMessage() приостанавливает поток до поступления сообщения (зависит от параметра времени ожидания).
                            Если у обработчика не создана очередь сообщений (или переполнена), то отправителю сообщается об ошибке.
                            2) Fork/RunMessage.
                            Создается новый поток, который немедленно запускается с адреса обработчика.
                            В стеке потока лежит сообщение (и больше ничего нет).

                            Цитата
                            Интерфейс - остановленный тред. При получении сообщения, он активизируется.

                            Это - классическая схема.
                            Но для обработки прерываний она не годится (синхронных сообщений).
                            Поэтому нужны RunMessage, а в KeyKOS подсказали хорошую идею добавить и ForkMessage.

                            Цитата
                            Можно сделать, что именно при объевлении интерфейса создается контекст треда

                            Один интерфейс может содержать несколько тредов одновременно!

                            Цитата
                            Получается такой механизм
                            В обработчик сообщения(остановленный тред) передается очередное сообщение (очередью управляет ядро). Этот обработчик создает новый тред, передав ему параметр-сообщение, а ядру возвращается MESSAGE_PENDING. Если это асинхронный вызов, вызвавший тред пробуждается.

                            У этой схемы серьезные недостатки.
                            Главное - не гарантируется мгновенная обработка приоритетных сообщений.

                            И еще момент, тоже важный:
                            Когда тред создает сам обработчик, он ему может присвоить приоритет не выше собственного.
                            Но логичнее, если приоритет ставит вызывающий процесс, согласно своим полномочиям (которые могут быть и выше).

                            Цитата
                            Хэндлы и указатели. и
                            Использование того или иного в конкретном случае будем рассматривать отдельно и желательно на готовом ядре(измерять производжительность будем).

                            ОК

                            Цитата
                            И для ядра часто(не всегда) удобней работать не хэндлами, а указателями. Т.е. оно сначало получает указатель объекта, а потом с ним работает. Так должно быть с секциями памяти.

                            Дело в том, что приложения идентифицируют секцию по хэндлу, так что указателями на секции не обойтись.
                              Цитата
                              Это - классическая схема.
                              Но для обработки прерываний она не годится (синхронных сообщений).
                              Поэтому нужны RunMessage, а в KeyKOS подсказали хорошую идею добавить и ForkMessage.

                              И еще как годится. Синхронность - вызвавший процесс ждет получения ответа, завершения обработки.

                              Честно говоря, мне не нравится идея ForkMessage.

                              Цитата

                              >Получается такой механизм
                              >В обработчик сообщения(остановленный тред) передается очередное сообщение ?
                              >(очередью управляет ядро). Этот обработчик создает новый тред, передав ему >параметр-сообщение, а ядру возвращается MESSAGE_PENDING. Если это асинхронный >вызов, вызвавший тред пробуждается.

                              У этой схемы серьезные недостатки.
                              Главное - не гарантируется мгновенная обработка приоритетных сообщений.

                              Первоначально приоритеты учитываются ядром, при постановки сообщения в очередь интерфейсу. И вызывается обработчик самого приоритетного.

                              А приоритет потока, то зачем ставить выше? Да и можно сделать, что поток интерфейса будет наследовать некоторые параметры вызываемого (например приоритет), или приоритет будет зависеть от приоритета сообщения, что лучше.

                              Так. И поток интерфейса - это не совсем обычный поток. У него контекст всегда сбрасывается. Это будет отдельный объект ядра.


                              Цитата
                              Дело в том, что приложения идентифицируют секцию по хэндлу, так что указателями на секции не обойтись.

                              Правильно. Приложения всегда будут работать с хэндлами. Но ядро  - лучше указатели. (повторюсь, что не для всего). Но для секций было бы очень удобно.
                                Цитата rcz, 02.10.03, 19:01:03

                                И еще как годится. Синхронность - вызвавший процесс ждет получения ответа, завершения обработки.

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

                                Цитата
                                Честно говоря, мне не нравится идея ForkMessage.

                                Чем?
                                Выглядит очень стройной.
                                Конечно, это лишние разновидности сообщений - зато они заменяют прерывания, межзадачные вызовы и порождение потоков.

                                Цитата
                                Первоначально приоритеты учитываются ядром, при постановки сообщения в очередь интерфейсу. И вызывается обработчик самого приоритетного.

                                Это нагружает ядро задачей упорядочивания сообщений. Более того, получим новую сущность: приоритет сообщения - в этой схеме это будет не совсем то же, что приоритет потока..

                                Цитата
                                И поток интерфейса - это не совсем обычный поток. У него контекст всегда сбрасывается. Это будет отдельный объект ядра.

                                Убрать его вообще - и не мучиться.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (21) « Первая ... 14 15 [16] 17 18 ...  20 21




                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0701 ]   [ 15 queries used ]   [ Generated: 18.07.25, 16:11 GMT ]