Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.133.141.6] |
|
Страницы: (29) [1] 2 3 ... 28 29 ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Привожу код из исходников линукса. Скажите, такое интенсивное использование препроцессорных средств делает его более профессионально выглядящим, или что?
Читать такой код очень трудно, какой смысл так писать? 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) 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) 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 Ешё, в чем заключается глубокий смысл таких конструкций? 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)? 450 #define spin_lock(lock) _spin_lock(lock) 451 #define write_lock(lock) _write_lock(lock) 452 #define read_lock(lock) _read_lock(lock) |
Сообщ.
#2
,
|
|
|
Цитата plan699 @ Ещё постоянно встречаются такие конструкции. Какой смысл определять spin_lock(lock) как _spin_lock(lock), а не сразу писать работающий код в spin_lock(lock)? смысл в том чтобы при изменении арзитектуры спин-лока надо было изменить тока макрос. например на хочеться добавить пару новых параметров , и при этом не хочеться переписывать килотонны кода. тогда мы просто меняем макрос на #define spin_lock(lock) _spin_lock(lock,0,0,0) к примеру и все. кончено можно обойтись и без макросов... и даже лучше обхъодиться без них.. |
Сообщ.
#3
,
|
|
|
plan699, сырцы Линукса -- не лучший пример для изучаения С.
На самом деле, код очень хорошо структурирован и отформатирован. Мне когда-то приходилось править исходники ядра -- никаких трудностей с их чтением у меня не возникло. Добавлено Цитата LuckLess @ На С -- не получится. кончено можно обойтись и без макросов... и даже лучше обхъодиться без них.. |
Сообщ.
#4
,
|
|
|
Цитата 1. Читать такой код очень трудно, 2. какой смысл так писать? 1. Да. 2. Довольно простой. Число kernel-hackers довольно мало. И стандарт для написания чего-либо для ядра выработан (см. документацию по исходникам ядра). Зачем что-то менять? Более того, многие из них знают этот код по причине того, что они сами его и написали. Второй момент. Более важный. В одном исходном тексте код и для многопроцессорной версии и для моно-процессорной версии. При сборе кода, просто выбирается нужный вариант. Это ещё как-то понятно. Но вот во-все не понять: #ifdef _WIN32 some shit #endif Цитата Ешё, в чем заключается глубокий смысл таких конструкций? В том, что макрос разворачивается в тело исполняемого кода. А вызов функции нагружает стек. В случае с ядром гораздо проще развернуть макрос (пусть и потеряв в объёме кода), нежели грузить стек. Снимите шляпу -- перед Вами ядро... :D:D:D Цитата Какой смысл определять spin_lock(lock) как _spin_lock(lock), а не сразу писать работающий код в spin_lock(lock)? В том, что c символа подчёркивания начинаются служебные/внутренние ф-ии. Интерфейсы к ним -- без оного. И ни кого не беспокоит как там именно реализовано в _spin_lock( lock ), т.к. конечный программист используется spin_lock( lock ). "Сокрытие деталей реализации". |
Сообщ.
#5
,
|
|
|
Цитата Relan @ На С -- не получится. в большинстве случаев получиться. как например в данном случае со spin_lock ... я же не говорю - совсем не использовать макросы. я говорю не использовать когда ненадо(точнее можно без них). |
Сообщ.
#6
,
|
|
|
А зачем писать
do{...}while(0) |
Сообщ.
#7
,
|
|
|
Цитата я говорю не использовать когда ненадо(точнее можно без них). Кхммм... Вообще говоря, код ядра -- штука, требующая трепетного обращения. И, при том, что макросы действительно лучше не использовать, в данном случае они могут быть оправданы по причинам производительности результирующего кода. Цитата А зачем писать Для того, чтобы компилятор не "фантазировал", по всей видимости. В данном случае блок операторов выделяется в отдельную функциональную единицу и подвергается своим правилам обработки (особенно, учитывая варианты опитимизации -- глобальное назначение регистров и т.д. и т.п.). По всей видимости, так. |
Сообщ.
#8
,
|
|
|
Цитата plan699 @ А зачем писать do{...}while(0) ? очень люблю эту конструкцию. чтобы выходить из блока break;-ом а не goto или строить тучу if-ов Добавлено к примеру if (func1()) { if (func2()) { if (func3()) { DoSmth() } } } я заменю на do { if (!func1()) break; if (!func2()) break; if (!func3()) break; DoSmth() } while(0) Добавлено Цитата the_Shadow @ Для того, чтобы компилятор не "фантазировал", по всей видимости. В данном случае блок операторов выделяется в отдельную функциональную единицу и подвергается своим правилам обработки (особенно, учитывая варианты опитимизации -- глобальное назначение регистров и т.д. и т.п.). По всей видимости, так. несогласен. хотя этот спор в холи вар надо... |
Сообщ.
#9
,
|
|
|
Кстати goto в ядре используется часто
Как вам например такая функция 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(). #define unlikely(x) __builtin_expect(!!(x), 0) #define __builtin_expect(x, expected_value) (x) А чтобы понять что такое task_rq() - смотрите код в первом сообщении |
Сообщ.
#10
,
|
|
|
имхо это все наследие былых времен..
когда имел смысл писать макросы т.к. компы были медленными и выиграшь в производительности был заметен, и когда goto не считался злом. а потом , из-за того что и так все хорошо работает , никто перепиской естественно не занимался. |
Сообщ.
#11
,
|
|
|
Цитата в данном случае они могут быть оправданы по причинам производительности результирующего кода. Канешна, ведь в сях нету шаблончиков. Вот где была бы красота. А с тех времён, когда процессоры были большие а программы маленькие осталось много нужного и полезного кода, который поддерживать - ну совершенно нету сил. А уж перенести на другую платформу - это вообще высший пилотажжж. |
Сообщ.
#12
,
|
|
|
BugHunter bot, какие шаблончики? Ты о чем? Ты еще boost и stl предложи. Или у вас уже разрешили использовать эти технологии и библиотеки в повседневной разработке? Ведь не только linux kernel hackers работают по принципу: "работает? работает правильно? работает быстро? ничего не трогай!"
|
Сообщ.
#13
,
|
|
|
Цитата и когда 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 |
Сообщ.
#14
,
|
|
|
Цитата Ведь не только linux kernel hackers работают по принципу: ага, Windows kernel тоже и ещё много разного кода |
Сообщ.
#15
,
|
|
|
Цитата BugHunter_bot, забани себя сам, а? За полнейшее непонимание того, что С делает... :D:D ну почему же, вот эти чтуки, приведённые здесь как раз на шаблончиках можно вполне переписать, и тоже всё будет compile-time . Добавлено Цитата Не в том суть. Суть в том, что ядро решает специфичные задачи и... весьма специфичным образом. Я обращаю ваше, коллеги, внимание на это ещё раз. а вот тут соглашусь |