Pull to refresh
151
0
Max Filippov @jcmvbkbc

low level freak

Send message
Добавил точную синхронизацию момента старта функции worker в потоках:

static int together;

void* f(void *p)
{
        __sync_add_and_fetch(&together,1);
        while(__sync_add_and_fetch(&together,0) < 2);
        worker();
}


Это превратилось в такой код:

f:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        subq    $8, %rsp
        movq    %rdi, -8(%rbp)
        lock addl       $1, together(%rip)
.L6:
        movl    $0, %edx
        movl    %edx, %eax
        lock xaddl      %eax, together(%rip)
        addl    %edx, %eax
        cmpl    $1, %eax
        jle     .L6
        movl    $0, %eax
        call    worker
        leave
        ret
        .cfi_endproc


и замедлило работу ~ в 100 (!!!) раз.

После укорачивания внешнего цикла в 100 раз результат такой:

2:      1
3:      1
4:      1
6:      4
7:      1
8:      9
9:      5
10:     7044
11:     99
12:     56
13:     98
14:     130
15:     350
16:     144
17:     291
18:     473
19:     304
20:     989


Т.е. ответ: «да, 2 достижима на практике» (:
#include <stdio.h>
#include <pthread.h>

static int counter;

void worker()
{
        int i;
        for (i = 1; i <= 10; i++)
                counter++;
}

void* f(void *p)
{
        worker();
}

int main()
{
        int i, r[22] = {};

        for(i = 0; i < 1000000 && counter != 2; ++i)
        {
                pthread_t t1, t2;
                counter = 0;
                pthread_create(&t1, NULL, f, NULL);
                pthread_create(&t2, NULL, f, NULL);
                pthread_join(t1, NULL);
                pthread_join(t2, NULL);
                ++r[counter];
        }
        for(i = 0; i < 22; ++i)
                printf("%d:\t%d\n", i, r[i]);
}


Цикл превратился в это:
worker:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movl    $1, -4(%rbp)
        jmp     .L2
.L3:
        movl    counter(%rip), %eax
        addl    $1, %eax
        movl    %eax, counter(%rip)
        addl    $1, -4(%rbp)
.L2:
        cmpl    $10, -4(%rbp)
        jle     .L3
        leave
        ret
        .cfi_endproc


Выводит:
0: 0
1: 0
2: 0
3: 0
4: 0
5: 0
6: 0
7: 0
8: 0
9: 0
10: 39
11: 3
12: 2
13: 2
14: 2
15: 3
16: 4
17: 3
18: 4
19: 9
20: 999929
21: 0
Только если вести БД пакетного менеджера у себя же в home.
А для установки наверняка понадобится делать chroot.
А для этого надо быть рутом либо иметь привилегию CAP_SYS_CHROOT.

А чтобы неподготовленная программа заработала без chroot, надо будет чтобы она нашла свои библиотеки (можно добиться установив LD_LIBRARY_PATH), а так же и остальные свои части (тут уже от программы самой зависит).
В целом, проще и правильнее будет её пересобрать из исходников, задав правильный --prefix для configure.
>> А вот если стоит do {...} while(false), то я знаю наверняка, куда мы попадём после break: в конец блока, который видно даже невооружённым беглым взглядом, кинутым по диагонали.

Как метка так и конец блока могут как быть так и не быть в пределах досягаемости беглого взгляда. Метка хороша тем, что это не какая-то безликая скобочка и ее можно найти поиском. И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.
Вот пример из linux:

int p54_read_eeprom(struct ieee80211_hw *dev)
{
        struct p54_common *priv = dev->priv;
        struct p54_eeprom_lm86 *eeprom_hdr;
        struct sk_buff *skb;
        size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
        int ret = -ENOMEM;
        void *eeprom = NULL;

        maxblocksize = EEPROM_READBACK_LEN;
        if (priv->fw_var >= 0x509)
                maxblocksize -= 0xc;
        else
                maxblocksize -= 0x4;

        skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
                            maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
                            GFP_KERNEL);
        if (!skb)
                goto free;
        priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
        if (!priv->eeprom)
                goto free;
        eeprom = kzalloc(eeprom_size, GFP_KERNEL);
        if (!eeprom)
                goto free;
...
еще пол экрана кода
...
        ret = p54_parse_eeprom(dev, eeprom, offset);
free:
        kfree(priv->eeprom);
        priv->eeprom = NULL;
        p54_free_skb(dev, skb);
        kfree(eeprom);

        return ret;
}
1. Да, могут. тут нужно чувство меры. как правило, если в выражении больше 3 бинарных логических операторов, то уже пора.
2. Да, будет непонятное выражение. Вот тут уже можно его и на стадии разбить. Ну и повторно использовать, если вдруг.
>Можно ли быстро понять, что тут написано?
>
>// ПЛОХО
>if (figureX > leftLimit && figureX < fightLimit && figureColor == GREEN)
>
>Подсветка, конечно, помогла бы, но и без подсветки следующее выражение читается на много проще:
>
>// ХОРОШО
>if (figureX > leftLimit &&
> figureX < fightLimit &&
> figureColor == GREEN)

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

if (isFigureTarget(figureX, figureColor))
Но широко распространенные компиляторы, типа gcc или msvc выделяют кадр стека один раз при входе в функцию и не меняют esp/ebp ходя по блокам внутри неё.

Кроме того, вызов конструктора и деструктора будет весить наверно больше, чем изменение размера кадра стека.
Думаю, все зависит от содержимого ваших /etc/inputrc и ~/.inputrc
И если вдруг нет этого man под рукой: linux.die.net/man/3/readline
Из man readline:
delete-char (C-d)
Delete the character at point. If point is at the beginning of the line, there are no characters in the line,
and the last character typed was not bound to delete-char, then return EOF.
Ctrl+w — убрать слово перед курсором

> От себя я скажу лишь то, что открыл их совершенно случайно, когда довольно сильно привык к emacs. И, к слову, интересно было бы узнать побольше подобного рода комбинаций, которые используются наиболее часто

man readline, чтобы было меньше случайностей и больше систематики. Там об этом написано.
… и тут же говорит совсем другое, правда на более поздней страничке: www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true
таки microsoft говорит, что по умолчанию оно вообще отключено в w2k и далее: technet.microsoft.com/en-us/kb/kb00244407.aspx
а заодно там же говорит, где поправить, чтобы работало
> А TAB, может кто не знал, умеет дополнять имена файлов и папок.
не TAB, а Ctrl+F по-умолчанию?
Действительно, в пакетах maemo5 ядро 2.6.27, а драйвер wi-fi — wl12xx. Теперь понятно, почему Nokia ссылалась на занятость своих инженеров в ответ на технические вопросы касательно stlc4560.
1) В этом проекте все тестировалось на реальном железе. В других проектах OSLL используется NS2.
2) Дело в том, что mac80211-based драйвера wi-fi — это тонкая прослойка, адаптирующая железо к mac-уровню, который в ядре представлен библиотекой mac80211.ko. Сам черновик стандарта 802.11s, реализованный проектом o11s, уже включен в состав mac80211. Драйвер же должен настроить железо для правильной рассылки маячков (beacon), установить правильный пакетный фильтр и скомпенсировать проявившиеся при этом особенности firmware. Исходный драйвер stlc45xx поддерживал только режим клиента точки доступа (managed), в котором станция не генерирует маячки. Так что всю маячковую инфраструктуру, общую для ad-hoc и mesh пришлось просто реализовать.
12 ...
40

Information

Rating
Does not participate
Location
Fremont, California, США
Registered
Activity