На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (29) [1] 2 3 ...  28 29  ( Перейти к последнему сообщению )  
> Вопрос к программистам на C , Исходники ядра Linux
    Привожу код из исходников линукса. Скажите, такое интенсивное использование препроцессорных средств делает его более профессионально выглядящим, или что?
    Читать такой код очень трудно, какой смысл так писать?

    ExpandedWrap disabled
      1 #ifndef _ASM_GENERIC_PERCPU_H_
      2 #define _ASM_GENERIC_PERCPU_H_
      3 #include <linux/compiler.h>
      4
      5 #define __GENERIC_PER_CPU
      6 #ifdef CONFIG_SMP
      7
      8 extern unsigned long __per_cpu_offset[NR_CPUS];
      9
      10 /* Separate out the type, so (int[3], foo) works. */
      11 #define DEFINE_PER_CPU(type, name) \
      12     __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
      13
      14 /* var is in discarded region: offset to particular copy we want */
      15 #define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
      16 #define __get_cpu_var(var) per_cpu(var, smp_processor_id())
      17
      18 /* A macro to avoid #include hell... */
      19 #define percpu_modcopy(pcpudst, src, size)                      \
      20 do {                                                            \
      21         unsigned int __i;                                       \
      22         for (__i = 0; __i < NR_CPUS; __i++)                     \
      23                 if (cpu_possible(__i))                          \
      24                         memcpy((pcpudst)+__per_cpu_offset[__i], \
      25                                (src), (size));                  \
      26 } while (0)
      27 #else /* ! SMP */
      28
      29 #define DEFINE_PER_CPU(type, name) \
      30     __typeof__(type) per_cpu__##name
      31
      32 #define per_cpu(var, cpu)                       (*((void)cpu, &per_cpu__##var))
      33 #define __get_cpu_var(var)                      per_cpu__##var
      34
      35 #endif  /* SMP */
      36
      37 #define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
      38
      39 #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
      40 #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)

    ExpandedWrap disabled
      286 #define cpu_rq(cpu)             (&per_cpu(runqueues, (cpu)))
      287 #define this_rq()               (&__get_cpu_var(runqueues))
      288 #define task_rq(p)              cpu_rq(task_cpu(p))
      289 #define cpu_curr(cpu)           (cpu_rq(cpu)->curr)

    ExpandedWrap disabled
      68 #ifndef RELOC_HIDE
      69 #define RELOC_HIDE(ptr, off)                                   \
      70   ({ unsigned long __ptr;                                       \
      71      __ptr = (unsigned long) (ptr);                             \
      72     (typeof(ptr)) (__ptr + (off)); })
      73 #endif


    Ешё, в чем заключается глубокий смысл таких конструкций?

    ExpandedWrap disabled
      559 #define sched_info_queued(t)            do { } while (0)
      560 #define sched_info_switch(t, next)      do { } while (0)
      19 #define percpu_modcopy(pcpudst, src, size)                      \
      20 do {                                                            \
      21         unsigned int __i;                                       \
      22         for (__i = 0; __i < NR_CPUS; __i++)                     \
      23                 if (cpu_possible(__i))                          \
      24                         memcpy((pcpudst)+__per_cpu_offset[__i], \
      25                                (src), (size));                  \
      26 } while (0)



    Ещё постоянно встречаются такие конструкции. Какой смысл определять spin_lock(lock) как _spin_lock(lock), а не сразу писать работающий код в spin_lock(lock)?

    ExpandedWrap disabled
      450 #define spin_lock(lock)         _spin_lock(lock)
      451 #define write_lock(lock)        _write_lock(lock)
      452 #define read_lock(lock)         _read_lock(lock)
    Сообщение отредактировано: plan699 -
      Цитата plan699 @
      Ещё постоянно встречаются такие конструкции. Какой смысл определять spin_lock(lock) как _spin_lock(lock), а не сразу писать работающий код в spin_lock(lock)?

      смысл в том чтобы при изменении арзитектуры спин-лока надо было изменить тока макрос.
      например на хочеться добавить пару новых параметров , и при этом не хочеться переписывать килотонны кода.
      тогда мы просто меняем макрос на
      #define spin_lock(lock) _spin_lock(lock,0,0,0)
      к примеру и все.
      кончено можно обойтись и без макросов...
      и даже лучше обхъодиться без них..
        plan699, сырцы Линукса -- не лучший пример для изучаения С. :)

        На самом деле, код очень хорошо структурирован и отформатирован. Мне когда-то приходилось править исходники ядра -- никаких трудностей с их чтением у меня не возникло.

        Добавлено
        Цитата LuckLess @
        кончено можно обойтись и без макросов...
        и даже лучше обхъодиться без них..
        На С -- не получится.
          Цитата
          1. Читать такой код очень трудно,
          2. какой смысл так писать?


          1. Да.
          2. Довольно простой. Число kernel-hackers довольно мало. И стандарт для написания чего-либо для ядра выработан (см. документацию по исходникам ядра). Зачем что-то менять? Более того, многие из них знают этот код по причине того, что они сами его и написали.

          Второй момент. Более важный. В одном исходном тексте код и для многопроцессорной версии и для моно-процессорной версии. При сборе кода, просто выбирается нужный вариант. Это ещё как-то понятно. Но вот во-все не понять:
          ExpandedWrap disabled
            #ifdef _WIN32
            some shit
            #endif


          Цитата
          Ешё, в чем заключается глубокий смысл таких конструкций?

          В том, что макрос разворачивается в тело исполняемого кода. А вызов функции нагружает стек. В случае с ядром гораздо проще развернуть макрос (пусть и потеряв в объёме кода), нежели грузить стек. Снимите шляпу -- перед Вами ядро... :D:D:D

          Цитата
          Какой смысл определять spin_lock(lock) как _spin_lock(lock), а не сразу писать работающий код в spin_lock(lock)?

          В том, что c символа подчёркивания начинаются служебные/внутренние ф-ии. Интерфейсы к ним -- без оного. И ни кого не беспокоит как там именно реализовано в _spin_lock( lock ), т.к. конечный программист используется spin_lock( lock ). "Сокрытие деталей реализации".
            Цитата Relan @
            На С -- не получится.

            в большинстве случаев получиться.
            как например в данном случае со spin_lock ...
            я же не говорю - совсем не использовать макросы.
            я говорю не использовать когда ненадо(точнее можно без них).
              А зачем писать
              ExpandedWrap disabled
                do{...}while(0)
              ?
                Цитата
                я говорю не использовать когда ненадо(точнее можно без них).

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

                Цитата
                А зачем писать

                Для того, чтобы компилятор не "фантазировал", по всей видимости. В данном случае блок операторов выделяется в отдельную функциональную единицу и подвергается своим правилам обработки (особенно, учитывая варианты опитимизации -- глобальное назначение регистров и т.д. и т.п.). По всей видимости, так.
                  Цитата plan699 @
                  А зачем писать

                  do{...}while(0)

                  ?


                  очень люблю эту конструкцию.
                  чтобы выходить из блока break;-ом а не goto или строить тучу if-ов

                  Добавлено
                  к примеру

                  ExpandedWrap disabled
                    if (func1())
                     {
                      if (func2())
                      {
                       if (func3())
                       {
                       DoSmth()
                       }
                      }
                     
                     }

                  я заменю на
                  ExpandedWrap disabled
                    do
                    {
                    if (!func1()) break;
                    if (!func2()) break;
                    if (!func3()) break;
                    DoSmth()
                    }
                    while(0)


                  Добавлено
                  Цитата the_Shadow @
                  Для того, чтобы компилятор не "фантазировал", по всей видимости. В данном случае блок операторов выделяется в отдельную функциональную единицу и подвергается своим правилам обработки (особенно, учитывая варианты опитимизации -- глобальное назначение регистров и т.д. и т.п.). По всей видимости, так.

                  несогласен.
                  хотя этот спор в холи вар надо...
                  Сообщение отредактировано: LuckLess -
                    Кстати goto в ядре используется часто
                    Как вам например такая функция
                    ExpandedWrap disabled
                      static runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
                          __acquires(rq->lock)
                      {
                          struct runqueue *rq;
                       
                      repeat_lock_task:
                          local_irq_save(*flags);
                          rq = task_rq(p);
                          spin_lock(&rq->lock);
                          if (unlikely(rq != task_rq(p))) {
                              spin_unlock_irqrestore(&rq->lock, *flags);
                              goto repeat_lock_task;
                          }
                          return rq;
                      }

                    Вроде бы заменить goto циклом здесь не представляет проблем.
                    Еще про эту же функцию. Вот что такое unlikely().
                    ExpandedWrap disabled
                      #define unlikely(x)     __builtin_expect(!!(x), 0)
                      #define __builtin_expect(x, expected_value) (x)

                    А чтобы понять что такое task_rq() - смотрите код в первом сообщении :)
                    Сообщение отредактировано: plan699 -
                      имхо это все наследие былых времен..
                      когда имел смысл писать макросы т.к. компы были медленными и выиграшь в производительности был заметен,
                      и когда goto не считался злом.

                      а потом , из-за того что и так все хорошо работает , никто перепиской естественно не занимался.
                      Сообщение отредактировано: LuckLess -
                        Цитата
                        в данном случае они могут быть оправданы по причинам производительности результирующего кода.

                        Канешна, ведь в сях нету шаблончиков. Вот где была бы красота.
                        А с тех времён, когда процессоры были большие а программы маленькие осталось много нужного и полезного кода, который поддерживать - ну совершенно нету сил. А уж перенести на другую платформу - это вообще высший пилотажжж.
                          BugHunter bot, какие шаблончики? Ты о чем? Ты еще boost и stl предложи. Или у вас уже разрешили использовать эти технологии и библиотеки в повседневной разработке? Ведь не только linux kernel hackers работают по принципу: "работает? работает правильно? работает быстро? ничего не трогай!"
                            Цитата
                            и когда goto не считался злом.

                            Всегда считался. От K&R.
                            Не в том суть. Суть в том, что ядро решает специфичные задачи и... весьма специфичным образом. Я обращаю ваше, коллеги, внимание на это ещё раз.

                            Цитата
                            несогласен.
                            хотя этот спор в холи вар надо...

                            Сколько угодно. :D:D:D

                            Проблема в том, что для HolyWar'а необходимо чётко понимать как работает gcc в части оптимизации. И есть моменты, когда оптимизацию нужно всячески блокировать, т.к. из неё ничего хорошего не выйдет. Код для SMP относится именно к этой области. По крайней мере, при инициализации SMP или механизмов, отличающихся в SMP от моно-процессорной системы. Если не ошибаюсь, то перед нами код, отвечающий за инициализацию sheduler'а. И здесь нужно быть крайне аккуратным. Почему -- объяснять?

                            Далее. По поводу goto. Единственный "вред" от него в том, что он:
                            - нарушает все правила "структурного программирования". Код становится слабо читаем.
                            - при выходе по goto из какой-либо конструкции, необходимо (ну, по крайней мере желательно) смотреть а что же собственно нужно за собой освободить. Не всегда освобождение каких-то ресурсов происходит автоматически. Приходится иногда и ручками... :D:D:D Собственно, goto в теле кода, как правило, приводит к генерации безусловного перехода. Ииии... Что делать, если за собой оно не очистило (перед goto) каких-то ресурсов? Просто, весьма велика вероятность ошибки...
                            Цитата
                            Вроде бы заменить goto циклом здесь не представляет проблем.

                            Угу. Только зачем, если goto всего одна инструкция (по большому счёту), а цикл -- как минимум две? ;) Если не больше. Зависит от способа организации цикла. Рекомендую "нарисовать" кусок кода и посмотреть на него с опцией -S gcc. причём, при разных уровнях оптимизации. Как минимум, без опт., -O, -O2. -O3 можно не рассматривать по причине того, что это, по большей части, для C++ и реализованных там механизмов (в частности, для инлайнинга).

                            Цитата
                            Канешна, ведь в сях нету шаблончиков. Вот где была бы красота.

                            BugHunter_bot, забани себя сам, а? За полнейшее непонимание того, что С делает... :D:D:D
                              Цитата
                              Ведь не только linux kernel hackers работают по принципу:

                              ага, Windows kernel тоже :yes:
                              и ещё много разного кода :whistle:
                                Цитата
                                BugHunter_bot, забани себя сам, а? За полнейшее непонимание того, что С делает... :D:D:D

                                ну почему же, вот эти чтуки, приведённые здесь как раз на шаблончиках можно вполне переписать, и тоже всё будет compile-time :).

                                Добавлено
                                Цитата
                                Не в том суть. Суть в том, что ядро решает специфичные задачи и... весьма специфичным образом. Я обращаю ваше, коллеги, внимание на это ещё раз.

                                а вот тут соглашусь
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (29) [1] 2 3 ...  28 29


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