Size: a a a

2021 March 11

DF

Dollar Føølish in pro.cxx
В целом mcas пока это просто программные абстракции так что спинлок тут неизбежен
источник

DF

Dollar Føølish in pro.cxx
Constantine Drozdov
вообще забавно, что построить lock-free можно, но для этого нужно на время транзакции запретить аллокатору переиспользовать память
А транзакционная память поможет тут ?
источник

СК

Сергей Казьмин... in pro.cxx
Всем привет. Возникла тут задача, мб кто-то подкинет идею, сам после нескольких часов раздумий
не смог родить что-то дельное.

Имеем структуру:
struct HookDescriptor
{
 using type = int(*)(int);
 
 static constexpr auto FuncName = "Func";
 static constexpr auto ModuleName = "Func";
 
 static void* originalFuncPtr;
 
 static int Handler(int a)
 {
   if (...)
   {
     return 0;
   }
   else
   {
     return reinterpret_cast<type>(originalFuncPtr)(a);
   }
 }
};

void*  HookDescriptor::originalFuncPtr = nullptr;

Стурктура описывает контекст некоторого хука, в котором участвует обработчик хука, указатель на оригинальную функцию,
плюсом имя оригинальной функции и имя dll.

Сценарий использования такой:
InstallHook(HookDescriptor::ModuleName, HookDescriptor::FuncName, &HookDescriptor::Handler, &HookDescriptor::originalFuncPtr);

Сейчас всё хорошо и удобно. Теперь представим, что таких хуков 50 разных и требуется как-то обобщить ввсё это дело.
Если оставить как есть, то надо собственноручно менеджить кучу всего: имена модулей и функций, объявления и определения обработчиков,
где-то хранить указатели на оригинальные функции, где-то тайпдефить сигнатуры.
Это чувствуется немного излишним.

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

Идеальный сценарий выглядит примерно так:

// API
int OriginalApiCall(int, int, int);
//

int Hook_OriginalApiCall(int, int, int)
{
 // тут хочется, чтобы можно было бы легко получить доступ к сигнатуре функции + originalFuncPtr
}

using MS = MagicStruct<ApiId, ModuleId>; // -- здесь проблема. Каждый хук однозначно определяется именем оригинального АПИ + именем модуля, в качестве строк в шаблон это просто так не запихнешь, поэтому допустим, что передаем значения из какого-нибудь enum-а

InstallHook(MS::ModuleName, MS::FuncName, &MS::Handler, &MS::originalFuncPtr);

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

Легко в принципе заиспользовать макросы и генерить всякие описательные структуры,
но думаю - вдруг есть что-то поэлегантнее...

Буду рад услышать идею или совет. Мб здесь и вовсе нет смысла городить магию
источник
2021 March 12

m

magras in pro.cxx
Dmitry Ulyumdzhiev
Порекомендуйте пожалуйста вводное описание как сделать atomic shared_ptr
В folly реализация мне понравилась. Они в старшие 15 бит 64 битного адреса упаковывают счетчик. При этом один shared_ptr обычно забирает сразу 2^15 ссылок из контрольного блока. При копировании пойнтера будет использоваться этот локальный счетчик, таким образом обычно достаточно одного cas.
источник

CD

Constantine Drozdov in pro.cxx
magras
В folly реализация мне понравилась. Они в старшие 15 бит 64 битного адреса упаковывают счетчик. При этом один shared_ptr обычно забирает сразу 2^15 ссылок из контрольного блока. При копировании пойнтера будет использоваться этот локальный счетчик, таким образом обычно достаточно одного cas.
А если не хватает - локаться? И в какой момент наращивают счётчик?
источник

SH

Serhii Herashchenko in pro.cxx
magras
В folly реализация мне понравилась. Они в старшие 15 бит 64 битного адреса упаковывают счетчик. При этом один shared_ptr обычно забирает сразу 2^15 ссылок из контрольного блока. При копировании пойнтера будет использоваться этот локальный счетчик, таким образом обычно достаточно одного cas.
А с адресом что тогда
источник

NK

Nikolay Kononov in pro.cxx
Serhii Herashchenko
А с адресом что тогда
ну типа это неиспользуемые биты
источник

SH

Serhii Herashchenko in pro.cxx
Nikolay Kononov
ну типа это неиспользуемые биты
А есть гарантии?
источник

NK

Nikolay Kononov in pro.cxx
64-битные операционные системы используют для адресации только 48-битные адреса
источник

NK

Nikolay Kononov in pro.cxx
(не все)
источник

NK

Nikolay Kononov in pro.cxx
источник

D

Dmitriy in pro.cxx
Nikolay Kononov
64-битные операционные системы используют для адресации только 48-битные адреса
Большинство. Boost.Lockfree целиком и полностью полагается на это, юзая tagged pointers
источник

NK

Nikolay Kononov in pro.cxx
Dmitriy
Большинство. Boost.Lockfree целиком и полностью полагается на это, юзая tagged pointers
ага, а еще фьютексы
источник

NK

Nikolay Kononov in pro.cxx
на которых вся многопоточка в линуксе
источник

m

magras in pro.cxx
Constantine Drozdov
А если не хватает - локаться? И в какой момент наращивают счётчик?
Если не хватает используют лок, который лежит в 16 бите, но это практически не должно происходить, потому что локальный счетчик пополняется когда израсходована половина, то есть 2^14 еще есть в запасе.
источник

NK

Nikolay Kononov in pro.cxx
Nikolay Kononov
на которых вся многопоточка в линуксе
в том числе std:: - кондвары, мьютексы и тд
источник

CD

Constantine Drozdov in pro.cxx
magras
Если не хватает используют лок, который лежит в 16 бите, но это практически не должно происходить, потому что локальный счетчик пополняется когда израсходована половина, то есть 2^14 еще есть в запасе.
А как пополнять тот, из которого забираем при чтении? туплю
источник

m

magras in pro.cxx
Serhii Herashchenko
А с адресом что тогда
На 64 битных системах адреса используют только 48 бит.
источник

DP

Denis Paukaev in pro.cxx
Nikolay Kononov
64-битные операционные системы используют для адресации только 48-битные адреса
это не ос не используют, это архитектура (x86-64) не поддерживает
источник

NK

Nikolay Kononov in pro.cxx
Denis Paukaev
это не ос не используют, это архитектура (x86-64) не поддерживает
да, согласен, оговорился
источник