Изучаем микроядро L4 и пишем приложение «Hello world» для системы Xameleon

    Если вы когда-либо изучали язык Си или сталкивались с новой средой разработки, то наверняка хотя бы раз писали простейшее приложение, выводящее «Hello world». Итак, один из возможных вариантов на языке Си:

    #include <stdio.h>
    int main(int argc, char * argv[], char * envp[])
    {
    puts("Hello world!");
    return 0;
    }

    Сохраним этот код в файл «hello.c» и с помощью компилятора gcc cоберём исполняемый файл используя следующую команду:
    gcc hello.c -o hello

    В результате, если на вашей системе установлен компилятор, файлы заголовков и библиотеки, получим исполняемый файл hello. Выполним его:
    ./hello

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

    Сначала немного теории и простых вещей. Попробуем собрать не исполняемый, а объектный файл. Для этого нам понадоится следующая команда:
    gcc -c hello.c
    в результате получаем объектный файл hello.o. Что характерно для объектных файлов? Их код позиционно независим, объектные файлы содержат таблицы импортируемых и экспортируемых функций и переменных и, что более интересно для нас, код мало зависит от программной платформы, но завязан на архитектуру процессора. Почему это важно, я расскажу далее, а сейчас пристальнее заглянем в содержимое объектного файла, используя следующую команду:
    objdump -hxS hello.o

    Заголовок объектного файла
    hello.o: file format elf32-i386
    hello.o
    architecture: i386, flags 0x00000011:
    HAS_RELOC, HAS_SYMS
    start address 0x00000000

    Используемые секции и их размер
    Sections:
    Idx Name Size VMA LMA File off Algn
    0 .text 0000002e 00000000 00000000 00000034 2**2
    CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
    1 .data 00000000 00000000 00000000 00000064 2**2
    CONTENTS, ALLOC, LOAD, DATA
    2 .bss 00000000 00000000 00000000 00000064 2**2
    ALLOC
    3 .rodata 0000000d 00000000 00000000 00000064 2**0
    CONTENTS, ALLOC, LOAD, READONLY, DATA
    4 .comment 00000012 00000000 00000000 00000071 2**0
    CONTENTS, READONLY
    5 .note.GNU-stack 00000000 00000000 00000000 00000083 2**0
    CONTENTS, READONLY

    Секция .text содержит ассемблерный код функции main программы hello. Как видно из примера, размер кода программы — 46 байт (0x24) Секция дата пустая, потому что наш пример не использует статические и глобальные переменные, которые бы хранились в этой секции. Наконец, секция .rodata размером 13 байт (0xd) содержит строку «Hello world!».

    Таблица экспортируемых и импортируемых объектов
    SYMBOL TABLE:
    00000000 l df *ABS* 00000000 hello.c
    00000000 l d .text 00000000 .text
    00000000 l d .data 00000000 .data
    00000000 l d .bss 00000000 .bss
    00000000 l d .rodata 00000000 .rodata
    00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
    00000000 l d .comment 00000000 .comment
    00000000 g F .text 0000002e main
    00000000 *UND* 00000000 puts

    В этой таблице нам интересны две последних строки — описание функции main, которая определена в нашей простейшей программе и описание внешней функции puts, которая определена где-то ещё.
    В принципе, если вы скомпилируете этот пример под Linux, а полученный исходный файл слинкуете под FreeBSD, то скорее всего он без проблем заработает. Верно и наоборот. А теперь заглянем в ассемблерный код нашей программы hello.c

    Disassembly of section .text:
    00000000 <main>:
      0:    8d 4c 24 04             lea    0x4(%esp),%ecx
      4:    83 e4 f0                 and    $0xfffffff0,%esp
      7:    ff 71 fc                 pushl -0x4(%ecx)
      a:    55                      push  %ebp
      b:    89 e5                    mov    %esp,%ebp
      d:    51                      push  %ecx
      e:    83 ec 04                 sub    $0x4,%esp
     11:    83 ec 0c                 sub    $0xc,%esp
     14:    68 00 00 00 00          push  $0x0
                15: R_386_32    .rodata
     19:    e8 fc ff ff ff          call  1a <main+0x1a>
                1a: R_386_PC32    puts
     1e:    83 c4 10                 add    $0x10,%esp
     21:    b8 00 00 00 00          mov    $0x0,%eax
     26:    8b 4d fc                 mov    -0x4(%ebp),%ecx
     29:    c9                      leave 
     2a:    8d 61 fc                 lea    -0x4(%ecx),%esp
     2d:    c3                      ret    


    * This source code was highlighted with Source Code Highlighter.
    Собственно говоря, это и есть ассемблерный код нашего приложения, созданный компилятором. Кстати, добро пожаловать в AT&T syntax style :)

    Это было просто, а теперь перейдём к более сложным вещам. Самый первый пример из статьи создаст исполняемый файл для вашей системы. В моём случае — Slackware Linux. Мы знаем, что содержимое объектного файла зависит от архитектуры процессора, но слабо зависит от операционной системы. Как же из полученного объектного файла создать исполняемый файл для системы Xameleon? Для этого необходимо связать (сликновать) объектный файл с библиотечными функциями Хамелеона.

    В нашем примере использована функция puts, определённая в заголовочном файле stdio.h Что же такое функция puts? Это функция, которая выводит строку и перевод строки в стандартный поток ввода/вывода.
    Например, функцию puts можно записать таким образом:

    int puts(char * str)
    {
    int status, len;

    len = strlen(str); // Считаем длину строки
    status = write( 1, str, len ); // Пишем строку в стандартный поток вывода
    if( status == len ) status = write( 1, "\n", 1 ); // Если нет ошибки, добавляем перевод строки
    if( status ==1 ) status += len;
    return status;
    }

    Можно «бесконечно» углубляться в дебри libc, но цель статьи — показать, как это работает в системе Хамелеон. Кстати, вышеописанный пример функции puts не претендует на оптимальность, он лишь демонстрирует пример простейшей функции. Вам остаётся только верить, что Хамелеоновская libc написана более оптимально. Впрочем, мы отвлеклись от темы повествования, поэтому вернёмся к делу и пристально посмотрим на функцию write. Эта функция определена в стандарте POSIX и именно она реализует взаимодействие нашего примера с операционной системой. Освежим свою память командой: man 2 write

    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);

    Наш пример пишет в файловый дескриптор номер 1, который по стандарту есть не что иное, как дескриптор стандартного потока вывода. Параметр buf — указатель на область памяти, содержащую данные для вывода (да, там будет адрес строки «Hello world»). Третий параметр — размер выводимых данных.

    Что отличает прикладного и системного программистов?
    Прикладной скажет: «Функция write выводит массив данных в открытый файл». Системный ответит: «Функция write передаёт системе файловый дескриптор, указатель на данные и количество байт для записи». Оба будут правы, но я хочу напомнить как называется этот блог. :)

    Итак, мы понимаем, что библиотечная функция write обращается к ядру операционной системы, поэтому нам надо понять, как это происходит. Поскольку система Хамелеон реализована поверх микроядра L4 Pistachio, то системный вызов — это IPC с двумя фазами:
    1. Фаза передачи — передаёт сервису файловой системы, который обслуживает функцию write, файловый дескриптор и L4 строку — тип данных, описывающий регион памяти.
    2. Фаза приёма -принимает от сервиса файловой системы статус выполнения операции.


    В документации Хамелеона системный вызов write описан следующим образом.

    Таким образом системный POSIX вызов write транслируется в IPC, показанный на рисунке выше.

    Исходный код библиотечной функции write, которая, с одной стороны обеспечивает POSIX write(), с другой — обеспечивает взаимодействие с ядром операционной системы:

    ssize_t write(
      int            nFileDescriptor,
      const void      *  pBuffer,
      size_t          nBytesWrite )
    {
      int            nStatus;
      int            nChunk;
      int            nTotalSent;
      char        *  pPointer;

      L4_MsgTag_t       tag;
      L4_Msg_t        msg;
      L4_StringItem_t     SendString;

      nStatus = nTotalSent = 0;
      pPointer = (char*) pBuffer;

      while ( nBytesWrite )
      {
        nChunk = (nBytesWrite > 4096) ? 4096 : nBytesWrite;
        SendString = L4_StringItem ( nChunk, (void*) pPointer );

        L4_Clear( &msg );
        L4_Set_Label( &msg, fsWriteFile );
        L4_Append( &msg, nFileDescriptor );
        L4_Append( &msg, &SendString );
        L4_Load( &msg );
        tag = L4_Call( fs_service_id );
        if ( L4_IpcFailed(tag) )
        {
          nStatus = nTotalSent ? nTotalSent : XAM_EINTR;
          break;
        }
        else
        {
          L4_Store( tag, &msg );
          nStatus = L4_Get( &msg, 0 );
          if( nStatus < 0 ) break;
          nTotalSent += nStatus;
        }

        pPointer  += nChunk;
        nBytesWrite -= nChunk;
      }

      // POSIX workaround
      if( nStatus < 0 )
      {
        errno = nStatus;
        nStatus = -1;
      }
      else
      {
        nStatus = nTotalSent;
      }

      return nStatus;
    }


    * This source code was highlighted with Source Code Highlighter.


    Выглядит как что-то новое от жадных разработчиков Хамелеона. Давайте пройдёмся по коду внимательнее и посмотрим, насколько он соответствует вызову WriteFile из документации. Первое, что бросается в глаза, это граничение размера буфера до 4-х килобайт. Это ограничение связано со спецификой проектирования модуля файловой системы — более длинные данные имеет смысл передавать другим системным вызовом, обеспечивающим временное отображение страниц запрашивающего процесса в адресное пространство сервиса файловой системы. Эта возможность уходит далеко за пределы простого Hello world, поэтому рассматривать её не будем.
    Следующие типы данных — структуры микроядра L4 Pistachio, используемые для обмена сообщениями
    • L4_MsgTag_t — тэг сообщения.
    • L4_Msg_t — структура, несущая данные сообщения.
    • L4_StringItem_t — строка L4

    Эти структуры определены в заголовочном файле message.h, микроядра L4 Pistachio.

    Следующий код готовит сообщение для передачи сервису файловой системы:
    SendString = L4_StringItem ( nChunk, (void*) pPointer ); // Подготовить дескриптор данных
    L4_Clear( &msg ); // Очистить сообщение
    L4_Set_Label( &msg, fsWriteFile ); // Установить идентификатор системного вызова
    L4_Append( &msg, nFileDescriptor ); // Добавить к сообщению дескриптор записываемого файла
    L4_Append( &msg, &SendString ); // Добавлить к сообщению записываемые данные
    L4_Load( &msg ); // Готовит сообщение к передаче


    Далее происходит системный вызов микроядра, который, собственно, и обеспечивает Inter Process Communication

    tag = L4_Call( fs_service_id );

    Где fs_service_id это переменная типа L4_ThreadId_t, содержащая идентификатор сервиса файловой системы. Как его получить, я расскажу ниже, когда перейдём к магии CRT (C RunTime code). А сейчас рассмотрим код, анализирующий ответ от сервиса файловой системы:

    if ( L4_IpcFailed(tag) )
    {
    nStatus = nTotalSent ? nTotalSent : XAM_EINTR;
    break;
    }
    else
    {
    L4_Store( tag, &msg );
    nStatus = L4_Get( &msg, 0 );
    if( nStatus < 0 ) break;
    nTotalSent += nStatus;
    }


    Если IPC оборвано, то проверяем, были ли переданы данные на предыдущей итерации и генерируем соответствующий код возврата. В случае корректного завершения IPC, обрабатываем код возврата.
    Описание функций используемых функций с префиксом L4_ можно увидеть в заголовочных файлах микроядра L4 Pistachio.

    Сложно? Думаю, да. Но мы уже близко к магии и байтсексу. Наступило время посмотреть внимательно на переменную fs_service_id. Система Хамелеон спроектирована таким образом, что изначально приложение не знает идентификатор сервиса файловой системы, поэтому его необходимо каким-то образом получить.

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

    static const char  szServiceName[3] = "fs"; // Внутреннее имя сервиса файловой системы

    L4_ThreadId_t  fs_service_id = L4_nilthread;

    extern "C" int xam_filesystem_init(void)
    {
      fs_service_id = GetDeviceHandle(szServiceName);
      return L4_IsNilThread(fs_service_id) ? XAM_ENODEV : 0;
    }


    * This source code was highlighted with Source Code Highlighter.


    Пройдёмся ещё глубже по коду и посмотрим реализацию функции GetDeviceHandle, возвращающую идентификатор запрашиваемого сервиса.

    extern L4_ThreadId_t  rootserver_id; // Главный обработчик Supervisor'а

    L4_ThreadId_t GetDeviceHandle(const char * szDeviceName)
    {
      L4_MsgTag_t           tag;
      L4_Msg_t            msg;
      L4_ThreadId_t          Handle;

      Handle = L4_nilthread;
      
      do {
      
        L4_Clear(&msg);
        L4_Set_Label(&msg, cmdGetDeviceHandle );
        L4_Append(&msg, L4_StringItem( 1+strlen(szDeviceName), (void*) szDeviceName) );
        L4_Load(&msg);
        tag = L4_Call( rootserver_id );
        if( L4_IpcFailed(tag) ) break;
        L4_Store( tag, &msg );
        Handle.raw = L4_Get(&msg, 1);
        
      } while( false );

      return Handle;
    }

    * This source code was highlighted with Source Code Highlighter.


    Можно провести аналогию с предыдущим примером, но отличие все же есть — это переменная rootserver_id, содержащая идентификатор Супервизора. Поскольку функции xam_filesystem_init и GetDeviceHandle вызываются из CRT, то идентификатор Supervisor'а необходимо получить до инициализации библиотеки.

    Каким образом прикладная задача может получить идентификатор Супервизора? Мы уже очень близко подошли к байтсексу, поэтому рассмотрим структуру данных, называемую Kernel Interface Page (KIP). Эта структура описана в спецификации микродяра L4 Pistachio и выглядит следующим образом:


    Поскольку супервизор — это первый пользовательский процесс с точки зрения микроядра, то его идентификатор можно получить на основании поля ThreadInfo из KIP. Особенность KIP в том, что микроядро держит эту страницу в единственном экземпляре, но отображает её в адресное пространство каждого процесса. Чтобы получить адрес KIP, процессу необходимо выполнить следующую последовательность команд:

        lock;    nop
        mov    %eax, kip


    Последовательность ассемблерных команд lock и nop вызовет исключение, которое перехватит микроядро и перед возвратом из исключения подставит в регистр EAX адрес Kernel Interface Page.

    Наконец, последний штрих — нахождение идентификатора обслуживающего потока Супервизора, на основе данных, полученних из Kernel Interface Page.

      mov  kip, %eax
      movw  198(%eax), %ax
      shrw  $4, %ax
      movzwl  %ax, %eax
      addl  $2, %eax
      sall  $14, %eax
      orl  $1, %eax
      movl  %eax, rootserver_id


    Таким образом модуль CRT0 в момент старта программы инициализирует библиотечные функции, совершающие обмен с различными сервисами системы Хамелеон.

    Уважаемые читатели, мне очень удивительно, что вас не сморил сон, что вы не закрыли окно браузера и нашли в себе силы дочитать до этого места. Вероятно, вам будет интересно «пощупать» свежую версию Инстрментария разработчика системы Xameleon.

    Спасибо за внимание.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 19

      +1
      занятно.
      в моей ОСи примерно такая же система взаимодействия.
      хотя с другой стороны, она же тоже микроядерная, так что сложно было что-то новое придумать.
      PS: скоро планирую написать статью как раз про создание собственного линкера, код у меня уже есть, но надо всё в кучу собрать.
        0
        Было бы интересно почитать, как раз сейчас копаюсь в структуре объектников и, в частности, в вопросах линковки.

        А что у Вас за ось, если не секрет? Можно ссылку?
          +1
          > Было бы интересно почитать, как раз сейчас копаюсь в структуре объектников и, в частности, в вопросах линковки.

          на этой неделе выложу статью. линкер в принципе модульный. Достаточно имплементировать интерфейс входного формата (у меня пока только COFF + зачатки ELF Relocable) и/или выходного (сейчас бинарный и своего собственного формата).

          > А что у Вас за ось, если не секрет? Можно ссылку?
          Пока она сугубо у меня на локалхосте, линкер — часть цикла о написании этой ОСи (причём, как ни странно — первая :) ). Собственно начав цикл и опишу эту ОСь.
            0
            Кстати, а Ваш подход весьма не плох. Не хочу пугать, говоря, что написание ОС — титанический труд, но написание своего линкера — это очень хороший ход. Я без иронии — сам мечтаю о линкёре, который бы мог бы связывать объектные файлы, созданные разными компиляторами, в пределах одной архитектуры. Например, слинковать объектные файлы, созаднные gcc и MS Visual C++. А если бы ещё ключиком можно было указать тип исполняемого формата, например Elf или PE, то этому линкёру цены бы не было.

            Я не знаю, напишите ли Вы свою ОС или нет, но знайте, что есть люди, которым интересен Ваш линкер. Удачи в осуществлении задуманного!

        +2
        Эцсамое, под «архитектурой» обычно понимается именно архитектура процессора — i686, x86_64, arm, mips. В результате выражения типа «объектный файл необходимо связать (сликновать) с библиотечными функциями требуемой архитектуры» и «исполняемый файл для родной архитектуры, на которой установлен компилятор. В моём случае — Slackware Linux» порядком рвут шаблон и заставляют задуматься о том, что же такое курил автор.
          0
          Спасибо за справедливое замечание. Ночь, усталость, спешка — получаются такие ляпы. Впредь буду внимателен к терминам, а статью исправлю, как только наберусь сил и приведу мысли в порядок.
          +1
          интересно, жду ещё
            0
            Вероятно, вам будет интересно «пощупать» свежую версию Инстрментария разработчика системы Xameleon.

            l4os.ru/license
            Исходный код системы и/или её подсистем, если это не оговорено отдельно, не распространяется и является собственностью их разработчиков.


            Спасибо, не интересно.
              0
              Спасибо за комментарий. Не желаю, чтобы в этой теме «светились» минусы за комментарии — каждый имеет право на своё мнение.

              Хотелось бы задать вопрос, а для чего Вам лично нужен исходный код? Исходный код какого модуля/сервиса Вам интересен?

              В нашем проекте пока (слава Богу) нет лойеров, поэтому лицензии пишем сами как умеем. Вот, к примеру, продукт, который распространяется в исходном коде. Его лицензия проста:

              Приобретая продукт, Вы имеете право:

              вносить любые изменения в исходный код;
              встраивать сервис в любые программные пакеты.

              Вы не имеете право:

              распространять исходные тексты продукта.


              Пусть это называется «лицензия Хамелеон».

              Что касается цитаты «собственность разработчиков», то наша команда готова предоставить разработчикам необходимые инструменты, а также мы готовы продвигать решения сторонних разработчиков для системы Хамелеон. Для этого случая и существует оговорка — «код принадлежит его разработчику». Т.е. если, не дай Бог, возникнут какие-либо разногласия, то автор кода вправе требовать не использовать его в проекте.
                0
                Хотелось бы задать вопрос, а для чего Вам лично нужен исходный код? Исходный код какого модуля/сервиса Вам интересен?

                Для удовлетворения собственного любопытства, разумеется. Читать, изучать, отлаживать, взламывать, улучшать, специализировать, генерализировать и т.д. Код — не роскошь.
                Это вдвойне странно, учитывая что есть другие реализации L4, открытые и свободные, взгляните на эту табличку.

                Его лицензия проста:

                Приобретая продукт, Вы имеете право:

                вносить любые изменения в исходный код;
                встраивать сервис в любые программные пакеты.

                Вы не имеете право:

                распространять исходные тексты продукта.

                Его лицензия противоречива: я встрою сервис в виде исходного кода в свой пакет и буду распространять исходные коды своего пакета. Зачем вы изобретаете велосипед на ровном месте?
                Закрадывается подозрение что и в исходном коде вашего продукта водятся подобные велосипеды.

                если, не дай Бог, возникнут какие-либо разногласия, то автор кода вправе требовать не использовать его в проекте.

                И что, будете изымать этот код из проданных экземпляров? (:
                  0
                  Простите, кажется уже второй раз отвечаю мимо комментария — не со злым умыслом, а по спешке и невнимательности. Мне, право, неудобно за свою неуклюжесть.

                0
                Для удовлетворения собственного любопытства, разумеется. Читать, изучать, отлаживать, взламывать, улучшать, специализировать, генерализировать и т.д. Код — не роскошь.

                Я Вас хорошо понимаю, но прошу понять и меня. Я потратил лучшие годы своей жизни на проект — ночи за компьютером, скандалы и развод с первой супругой, отказ от выгодных предложений работы (в том числе в заграничных компаниях). И всё это для того, чтобы мог заниматься любимым делом и верить, что рано или поздно проект даст плоды. Сейчас, когда Linux похоронил несколько коммерческих операционных систем, его путь повторить невозможно — место занято.

                Это вдвойне странно, учитывая что есть другие реализации L4, открытые и свободные, взгляните на эту табличку.

                Дык, Хамелеон построен сверху Pistachio, а Pistachio распространяется под Two Clause BSD license. Но я Вам так скажу, насколько бы прекрасно не было Pistachio (а это микроядро прекрасно), его спецификация ещё лучше: www.l4ka.org/l4ka/l4-x2-r7.pdf — это одна из лучших спецификаций, с которыми мне приходилось сталкиваться за всю карьеру разработчика.
                И вот под какой лицензией она распространяется:

                Permission to copy and distribute verbatim copies of this specification in any medium for any purpose without fee or royalty is hereby granted. No right to
                create modifications or derivates is granted by this license. The L4Ka Team may make changes to this specification at any time, without notice. The latest
                revision of this document is available at l4ka.org/.

                No modifications nor derivates

                Его лицензия противоречива: я встрою сервис в виде исходного кода в свой пакет и буду распространять исходные коды своего пакета. Зачем вы изобретаете велосипед на ровном месте?

                Легко. Вы можете встраивать сервис под любой лицензией, если она прямо не запрещает использовать продукт совместно с Хамелеоном. Хоть под MS EULA, если EULA этого не запрещает.

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

                Хмм. Ядро (которое поверх микроядра и ниже userspace) уже превысило 100 тыс. строк. Вероятно, там есть и велосипеды, и баги, и светлые идеи, а также максимально оптимизированные места соседствуют с кодом, написанным «на авось» и «потом переделаю». Меня радует уже то, что когда писал libc, хватило ума не изобретать велосипед, а обратиться к стандарту POSIX. Т.ч. насчёт велосипедов — я не согласен.

                Помимо этого Хамелеон использует несколько оригинальных алгоритмов, которые назвать велосипедом — язык не поворачивается. Например, L4 позволяет аллокировать страницы виртуальной памяти с размером, отличным от размера страниц поддерживаемым архитектурой процессора. Грех было этим не воспользоваться и не написать свою реализацию работы с памятью. Насколько я знаком со внутренней архитектурой Linux и Windows, они используют другие принципы работы с виртуальной памятью.

                И что, будете изымать этот код из проданных экземпляров? (:

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

                Наконец, используя API, предоставляемое Хамелеоном, Вы можете распространять модули без исходного кода. Например, Вы разработали драйвер звуковой карты и согласовали с нами его системные вызовы. Мы можем договориться о включении этого драйвера в систему даже без исходного кода. Т.е. Ваши идеи и наработки останутся Вашими и если в какой-то момент Вам покажется, что сотрудничество не выгодно, или другой разработчик предложит Вам более выгодные условия, взамен потребовав убрать код из других систем, то сможете это сделать просто известив нас об этом. Что касается протокола взаимодействия с Вашим драйвером, то тут всё сложнее — мы не заинтересованы в потере протоколов. Даже не знаю, как быть в такой случае.

                  0
                  Я потратил лучшие годы своей жизни на проект — ночи за компьютером, скандалы и развод с первой супругой, отказ от выгодных предложений работы (в том числе в заграничных компаниях). И всё это для того, чтобы мог заниматься любимым делом и верить, что рано или поздно проект даст плоды.

                  Довольно эмоциональный пассаж, призванный как бы разжалобить читающего/будущего покупателя. Кстати, между «чтобы» и «мог» пропущено местоимение «я». Как бы это помягче сказать… Это ваше личное дело, как вы разрабатываете — молитесь ли вы на код, приносите ли вы ему человеческие жертвы, делаете ли вы на него ставки, света белого не видите, или как-либо ещё. Ничто из этого не сделает плохой код лучше, а хороший код не испортит.

                  Дальше, выделение в цитате — моё.
                  [...]
                  его спецификация ещё лучше
                  [...]
                  И вот под какой лицензией она распространяется:

                  Permission to copy and distribute verbatim copies of this specification in any medium for any purpose without fee or royalty is hereby granted. No right to
                  create modifications or derivates is granted by this license. The L4Ka Team may make changes to this specification at any time, without notice. The latest
                  revision of this document is available at l4ka.org/.


                  Во-первых это спецификация и она открытая. Да, она не полностью свободная. Код — полностью свободный. Согласитесь, большая разница с тем что предлагаете вы.

                  Вообще, идея, которую я хотел донести с самого начала состоит в том, что закрытость проекта — неслабый отталкивающий фактор для некоторых разработчиков.
                    0
                    Т.ч. насчёт велосипедов — я не согласен.


                    Ммм, habrahabr.ru/qa/6793/ — это ваш велосипед с квадратными колёсами? Тот самый?
                      0
                      Тот самый. Уважаемый gribozavr не затрудняясь сломал сервер и вытянул его исходный код. В приватном сообщении он рассказал, каким образом удалось сломать — я ему очень за это благодарен — мне урок, ему почёт и уважение.

                      Таки мне есть чем возразить на велосипед с квадратными колёсами. Много Вы знаете FTP серверов для POSIX систем, не использующих функцию select()?

                      Появление этого «велосипеда с квадратными колёсами» объяснить очень просто — мне было необходимо отлаживать TCP/IP стек, а для такой задача FTP протокол подходит как нельзя лучше — во первых, протокол подразумевает как исходящие, так и входящие TCP соединения, во вторых, можно передавать большие объёмы информации в обе стороны. Лучшего теста для TCP/IP стека не придумаешь. При том, что существуют десятки, если не сотни, FTP клиентов для различных платформ. Можно ли придумать лучший тест? И это с учётом того, что мой велосипед «заточен» именно под отладку TCP/IP стека — пишет тонны отладочной информации в stdout и stderr.
                      Т.ч. я бы не был на Вашем месте столь категоричен. :)

                        0
                        Много Вы знаете FTP серверов для POSIX систем, не использующих функцию select()?

                        Студенческая лаба? Из серьёзных — ни одного не знаю.
                        А в чём особенная доблесть использования/не использования select?
                          0
                          С функцией sеlect очень удобно писать сетевые программы. Многие вещи упрощаются — из одного процесса и потока можно обслуживать несколько сокетов. Например, классический FTP сервер форкается при каждом новом соединении, при этом управляющий канал и канал данных обслуживаются через select — всё красиво и просто. Что даёт? Например, при посылке или приёме большого файла, вы можете послать по управляющему каналу команду ABORT.

                          Неиспользование select, это не доблесть, а ограничение — в Хамелеоне не реализован системный вызов select — ни в сетевой подсистеме, ни в файловой. Он поэтому и не реализован, потому что по стандарту этот системный вызов может принимать как дескрипторы файлов, так и дескрипторы сокетов, но вот беда — в отличие от монолитных, в микроядерных системах сетевой сервис и файловый сервис могут быть совершенно разными независимыми процессами. Более того, в какой либо конфигурации может не быть сетевой системы, а в другой конфигурации может не быть файловой. По логике — нужно писать отдельный диспетчер для select и других вызовов, с другой стороны не хочется плодить лишние сущности. И пока чаша весом не перевесила ни в одну сторону, было сказано: «Хрен с ним, пусть пока работает без select».

                            +1
                            Он поэтому и не реализован, потому что по стандарту этот системный вызов может принимать как дескрипторы файлов, так и дескрипторы сокетов, но вот беда — в отличие от монолитных, в микроядерных системах сетевой сервис и файловый сервис могут быть совершенно разными независимыми процессами

                            Мне кажется, что в select редко складывают разнородные дескрипторы, а в тех случаях когда это делают, код понятным образом можно разделить на два потока, обрабатывающих дескрипторы разных классов. Более «ровным», на мой поверхностный, без знания внутренностей взгляд, решением было бы реализовать select и там и там, и ругаться когда в него передаётся смешанный набор дескрипторов.
                              0
                              Спасибо. Я тоже склоняюсь к такому мнению. Тем более, если будет реализация select в двух местах, то при необходимости не составит особо труда написать обвязку для смешивания.

                              Пожалуй, мне понадобится некоторое время на реализацию хотя бы в сетевом сервисе.

                  Only users with full accounts can post comments. Log in, please.