cli на многопроцессороной машине
От: sergei_132 http://sergbox.blogspot.com
Дата: 13.06.06 14:57
Оценка:
если я сделаю cli в драйвере, то прерывания запретятся только на 1 процессоре? или на всех? если только на одном, как тогда запретить прерывания на всех процессорах?
Re: cli на многопроцессороной машине
От: Leo Yuriev Россия https://github.com/erthink
Дата: 13.06.06 15:10
Оценка: 2 (1)
Здравствуйте, sergei_132, Вы писали:

_>если я сделаю cli в драйвере, то прерывания запретятся только на 1 процессоре? или на всех? если только на одном, как тогда запретить прерывания на всех процессорах?


Конечно только на одном. Если на всех то как сделать это сильно зависит от ОС. В Linux и FreeBSD все просто (см. sources), в W2K/XP сложнее — примерно так http://www.bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=106560
Re: cli на многопроцессороной машине
От: TarasCo  
Дата: 13.06.06 15:28
Оценка: 1 (1) :)
Здравствуйте, sergei_132, Вы писали:

_>если я сделаю cli в драйвере, то прерывания запретятся только на 1 процессоре? или на всех? если только на одном, как тогда запретить прерывания на всех процессорах?


1. Главный вопрос: зачем? От этого будет зависеть ответ.
Да пребудет с тобою сила
Re[2]: cli на многопроцессороной машине
От: sergei_132 http://sergbox.blogspot.com
Дата: 13.06.06 15:58
Оценка:
можно ли так сделать: на каждом процессоре поставить в очередь Dpc, и в каждой DpcFn сделать cli ???


for(j=0;j<NumberProcessors;j++)
{
    KeSetTargetProcessorDpc(&Dpc,(CCHAR)j);
    KeSetImportanceDpc(&Dpc,HighImportance);
    p=(PVOID)&j;
    KeInsertQueueDpc(&Dpc,p,(PVOID)NULL);
}

VOID DpcFn(..)
{
    cli
}
Re[3]: cli на многопроцессороной машине
От: sergei_132 http://sergbox.blogspot.com
Дата: 13.06.06 16:00
Оценка:
OS Win2k/Xp
Re[3]: cli на многопроцессороной машине
От: sergei_132 http://sergbox.blogspot.com
Дата: 13.06.06 17:52
Оценка:
вернее вот так:

KDPC Dpc[MAXIMUM_PROCESSORS];

ULONG n=NumberProcessors;

for(CCHAR i = 0; i < NumberProcessors; i++)
{
    KeInitializeDpc(&Dpc[i], DpcRoutine, NULL);
    KeSetImportanceDpc(&Dpc[i], LowImportance);
    KeSetTargetProcessorDpc(&Dpc[i], i);
}

for(CCHAR i = NumberProcessors-1; i >= 0; i--)
{
    KeInsertQueueDpc(&Dpc[i], 0, 0);
}

VOID DpcRoutine(..)
{
    n--;
    cli
    if (n==0) {do something... when  cli all processors...}
}
Re[4]: cli на многопроцессороной машине
От: Leo Yuriev Россия https://github.com/erthink
Дата: 13.06.06 19:03
Оценка: 43 (2)
Здравствуйте, sergei_132, Вы писали:


_>вернее вот так:

_>KDPC Dpc[MAXIMUM_PROCESSORS];
_>ULONG n=NumberProcessors;
_>for(CCHAR i = 0; i < NumberProcessors; i++)
_> {
_> KeInitializeDpc(&Dpc[i], DpcRoutine, NULL);
_> KeSetImportanceDpc(&Dpc[i], LowImportance);
_> KeSetTargetProcessorDpc(&Dpc[i], i);
_> }
_>for(CCHAR i = NumberProcessors-1; i >= 0; i--)
_>{
_> KeInsertQueueDpc(&Dpc[i], 0, 0);
_>}
_>VOID DpcRoutine(..)
_>{
_>n--;
_>cli
_>if (n==0) {do something... when cli all processors...}
_>}

Нет, нельзя. cli можно делать только после того как каждая DPC доставленна до выбранного процессора. Если это сделать раньше, то cli заблокирует IPI (Inter-Processor Interrupt) и в результате KeInsertQueueDpc() может зациклится на ожидании ответа от dpc-target-cpu.

Вот продуманная работающая реализация:
    class TSingleProcessorMode
    {
        volatile LONG Hub;
        KDPC DpcArray[MAXIMUM_PROCESSORS];
        static void DpcRoutine(KDPC *pDpc, void *pContext, void *pArg1, void *pArg2);
    public:
        void Initialize();
        void Execute(void (__fastcall *Routine)(void *), void *pContext);
    };

    void TSingleProcessorMode::Initialize()
    {
        RtlZeroMemory(this, sizeof(TSingleProcessorMode));
        if(GetNumberOfProcessors() > 1)
            for(int i = 0; i < MAXIMUM_PROCESSORS; i++)
            {
                KeInitializeDpc(&DpcArray[i], DpcRoutine, this);
                KeSetTargetProcessorDpc(&DpcArray[i], (CCHAR) i);
                KeSetImportanceDpc(&DpcArray[i], HighImportance);
            }
    }

    void TSingleProcessorMode::DpcRoutine(KDPC *pDpc, void *pContext, void *pArg1, void *pArg2)
    {
        TSingleProcessorMode *pThis = (TSingleProcessorMode *) pContext;
#if _WIN32_WINNT < 0x0502
        KeRaiseIrqlToSynchLevel();
#else
        KIRQL DummyIrql;
        KeRaiseIrql(SYNCH_LEVEL, &DummyIrql);
#endif

        while(true)
        {
        #if !defined(_M_IX86) || defined(ENABLE_COLLECT_PERFORMANCE)
            KIRQL DummyIrql;
            KeRaiseIrql(HIGH_LEVEL, &DummyIrql);
        #else
            __asm
            {
                pushfd
                cli
            }
        #endif
            LONG probe, level = InterlockedDecrement(&pThis->Hub) << 8;
            if(level == 0)
            {
                ((void(__fastcall *)(void*))pArg1)(pArg2);
                InterlockedExchange(&pThis->Hub, -1);
            exit:
            #if defined(_M_IX86) && !defined(ENABLE_COLLECT_PERFORMANCE)
                __asm
                {
                    popfd
                }
            #endif
                KeLowerIrql(DISPATCH_LEVEL);
                return;
            }

            do
            {
                PERFORMANCE_AUTO_COUNT;
                __Crt::ProcessorPause();
                probe = pThis->Hub;
                if(probe < 0)
                    goto exit;
            }
            while(probe == 0 || --level >= 0
            || InterlockedCompareExchange(&pThis->Hub, probe + 1, probe) != probe);

        #if !defined(_M_IX86) || defined(ENABLE_COLLECT_PERFORMANCE)
            KeLowerIrql(SYNCH_LEVEL);
        #else
            __asm
            {
                popfd
            }
        #endif
            PERFORMANCE_AUTO_COUNT;
            __Crt::ProcessorPause();
        }
    }

OPTIMIZE_FOR_SIZE

    void TSingleProcessorMode::Execute(void (__fastcall *pRoutine)(void *), void *pContext)
    {
        KeEnterCriticalRegion();
        FlushQueuedDpcs();
        if(GetNumberOfProcessors() > 1)
        {
            KAFFINITY ActiveProcessors = KeQueryActiveProcessors();
            KIRQL Irql;
            KeRaiseIrql(DISPATCH_LEVEL, &Irql);
            {
                Hub = CountBits(ActiveProcessors);
                unsigned i;
                while(_BitScanReverse(i, ActiveProcessors))
                {
                    do
                    {
                        KAFFINITY Mask = 1ul << i;
                        if((ActiveProcessors & Mask) != 0
                        && (i != KeGetCurrentProcessorNumber() || ActiveProcessors == Mask))
                        {
                            ActiveProcessors &= ~Mask;
                            KeInsertQueueDpc(&DpcArray[i], pRoutine, pContext);
                        }
                    }
                    while((int)--i >= 0);
                }
            }
            KeLowerIrql(Irql);
        }
        else
        {
#if !defined(_M_IX86) || defined(ENABLE_COLLECT_PERFORMANCE)
            KIRQL SavedIrql;
            KeRaiseIrql(HIGH_LEVEL, &SavedIrql);
#else
            _disable();
#endif

            pRoutine(pContext);
#if !defined(_M_IX86) || defined(ENABLE_COLLECT_PERFORMANCE)
            KeLowerIrql(SavedIrql);
#else
            _enable();
#endif
        }
        FlushQueuedDpcs();
        KeLeaveCriticalRegion();
    }

#pragma code_seg(pop)
Re[5]: cli на многопроцессороной машине
От: sergei_132 http://sergbox.blogspot.com
Дата: 13.06.06 19:40
Оценка:
спасибо, но зачем же свой код давать ? просто бы сказали в чем ошибка... А то ведь так совсем можно облениться и ничего самому не делать...
Re[4]: cli на многопроцессороной машине
От: Геннадий Майко США  
Дата: 14.06.06 06:40
Оценка:
Здравствуйте, sergei_132,


_>VOID DpcRoutine(..)

_>{
_>n--;
_>cli
_>if (n==0) {do something... when cli all processors...}
_>}
--
А почему нужно именно запретить прерывания на процессорах? Может быть, можно обойтись маскированием внешних прерываний, поднимая IRDL до HIGH_LEVEL?

C уважением,
Геннадий Майко.
Re[5]: cli на многопроцессороной машине
От: Andrew.W Worobow https://github.com/Worobow
Дата: 14.06.06 14:59
Оценка:
Здравствуйте, Геннадий Майко, Вы писали:

IRQL на каждом процессоре свой... Придётся также поднимать его для каждого процессора.
Не все кто уехал, предал Россию.
Re[6]: cli на многопроцессороной машине
От: Геннадий Майко США  
Дата: 14.06.06 18:01
Оценка:
Здравствуйте, Andrew.W Worobow,

AWW>IRQL на каждом процессоре свой... Придётся также поднимать его для каждого процессора.

--
Безусловно; именно это я и имел в виду — поднять IRQL на каждом процессоре вместо выполнения специальной команды процессора.

C уважением,
Геннадий Майко.
Re[7]: cli на многопроцессороной машине
От: Serjio Россия  
Дата: 29.06.06 07:18
Оценка:
>Безусловно; именно это я и имел в виду — поднять IRQL на каждом процессоре вместо выполнения специальной команды процессора.

О чем, в свое время
Автор: Геннадий Майко
Дата: 29.05.05
, Вами, мне была присланна, ссылка.
которую с благодарностью вспоминаю
Только на РСДН помимо ответа на вопрос, можно получить еще список орфографических ошибок и узнать что-то новое из грамматики английского языка (c) http://www.rsdn.ru/forum/cpp/4720035.1.aspx
Автор: ZOI4
Дата: 28.04.12
Re[2]: cli на многопроцессороной машине
От: CoolCmd Россия  
Дата: 31.12.07 14:03
Оценка:
Здравствуйте, Leo Yuriev, Вы писали:

_>>если я сделаю cli в драйвере, то прерывания запретятся только на 1 процессоре? или на всех? если только на одном, как тогда запретить прерывания на всех процессорах?

LY>Конечно только на одном.
А если процессор один, но многоядерный, например core2duo?
простите, я убил небо
Re[3]: cli на многопроцессороной машине
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 03.01.08 07:21
Оценка: 1 (1)
Здравствуйте, CoolCmd, Вы писали:

CC>А если процессор один, но многоядерный, например core2duo?


Ядро многоядерного процессора можно отличить от процессора в отдельном корпусе только путем анализа идентификационных данных самого процессора или окружающего его железа.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: cli на многопроцессороной машине
От: Ivan Россия www.rsdn.ru
Дата: 09.01.08 11:55
Оценка: 17 (2)
Здравствуйте, sergei_132, Вы писали:

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


кстати, когда я в отладчике пытался посмотреть как hotpatching в режиме ядра атомарно меняет исполняемый код, мне попались интересные функции:

KeGenericCallDpc(PKDPC Dpc, PVOID) и
(вызываются внтури dpc) KeSignalCallDpcSynchronize, KeSignalCallDpcDone

насколько я понял, это встроенная в ОС реализация барьеров, dpc шедулится на каждый из процессоров, внутри dpc синхронищация с помощью KeSignalCallDpcSynchronize, кому-то одному KeSignalCallDpcSynchronize вернет TRUE, остальным FALSE, т.е. псевдокод dpc выглядит как-то так:
{
    if(KeSignalCallDpcSynchronize)
    {

    }
    KeSignalCallDpcSynchronize
    KeSignalCallDpcDone
}
Re[7]: cli на многопроцессороной машине
От: Unmanaged Россия ICQ 476611995
Дата: 09.01.08 14:06
Оценка:
I>KeGenericCallDpc(PKDPC Dpc, PVOID) и
I>(вызываются внтури dpc) KeSignalCallDpcSynchronize, KeSignalCallDpcDone

К сожалению, все перечисленные функции, как и сам Hot-Patching, доступны начиная только с Windows Server 2003.
STATUS_INVALID_DEVICE_REQUEST
Re[8]: cli на многопроцессороной машине
От: gear nuke  
Дата: 15.01.08 04:56
Оценка:
Здравствуйте, Unmanaged, Вы писали:

U>К сожалению, все перечисленные функции, как и сам Hot-Patching, доступны начиная только с Windows Server 2003.


Это не важно. Теперь есть "документированный правильный способ" (обрати внимание на выравнивание заглушек для hot-patching) и — все остальные .
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[5]: cli на многопроцессороной машине
От: Adios  
Дата: 11.05.08 05:16
Оценка:
>Вот продуманная работающая реализация:
/.../

Подскажите, пожалуйста, что за функция __Crt::ProcessorPause() и что она делает, или хотя бы где её искать.
А так же для чего:
PERFORMANCE_AUTO_COUNT;
ENABLE_COLLECT_PERFORMANCE;
__asm pushfd;
Re: cli на многопроцессороной машине
От: Maxim S. Shatskih Россия  
Дата: 13.05.08 12:44
Оценка:
_>если я сделаю cli в драйвере, то прерывания запретятся только на 1 процессоре? или на всех?

На одном.

_> если только на одном, как тогда запретить прерывания на всех процессорах?


Стандартных средств нет. Нужно делать processor corral — т.е. отправкой DPC с выставленной affinity побуждать все CPU выполнять код, содержащий cli.

Зачем это надо-то? хуки ставим?
Занимайтесь LoveCraftом, а не WarCraftом!
Re[6]: cli на многопроцессороной машине
От: remark Россия http://www.1024cores.net/
Дата: 27.05.08 00:29
Оценка:
Здравствуйте, Adios, Вы писали:

A>Подскажите, пожалуйста, что за функция __Crt::ProcessorPause() и что она делает, или хотя бы где её искать.


Это видимо инструкция pause на x86, или интринсик _mm_pause() в msvc.
Для других процессоров — не знаю.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.