2013-02-19 2 views
3

При некоторых условиях я хочу запланировать таймер (struct timer_list), который работает с пользовательскими данными. function поле этой структуры имеет действительную функцию, которая будет вызвана, и определяется следующим образом:Как передать пользовательский аргумент функции таймера linux?

void (*function)(unsigned long); 

Дело в том, я хочу передать указатель вместо unsigned long. Я знаю, что в зависимости от архитектуры преобразование int-ptr может быть или не быть безопасным, но я не мог найти, если все архитектуры выравнивают целые числа long с указателями, так что вот мой вопрос (на самом деле, два в одном) :

Безопасно ли выполнить команду long? void* литье? Если нет, как мне обрабатывать аргумент unsigned long, чтобы получить указатель данных, который я хочу в функции таймера?

+0

Я бы этого не сделал. Должна быть причина, что параметр имеет тип unsigned long. Есть ли доступ к этой странице? –

+0

@ bash.d Единственный комментарий для этого в manpage 'add_timer' и друзей заключается в том, что аргумент будет использоваться для разграничения между таймерами, которые выполняют одну и ту же функцию. В этом ничего нет. – Rerito

+0

Ну, тогда попробуй пойти с предложением Иоакима. Я бы не бросил вообще! –

ответ

2

Вы можете использовать переданное число как индекс в массив, содержащий вашу настраиваемую структуру данных.

+0

Я выхожу из вашего ответа, что единственное ограничение на 'long' - это должно быть как минимум 32-битное, и что кастинг на указатель небезопасен, правильно? – Rerito

+1

@Rerito Правильно, это небезопасно для приведения типов в/из указателей, и размер может отличаться. –

+0

Таким образом, кажется, что единственным решением было бы иметь некоторую глобальную переменную, хранящую пары (длинные, данные). Как и массив, который вы предложили, или любые динамические структуры (я думал об использовании деревьев, индексированных ключом «long»). Во всяком случае, ответ принят! – Rerito

4

В случае функций таймера и в некоторых других ситуациях можно просто привести указатель на структуру данных в unsigned long, хранить его в data области struct timer_list и бросил аргумент функции таймера обратно в указатель на вашу структуру данных. Это, по-видимому, обычная практика.

Linux Driver Development, 3rd. ed. состояния следующее по этому вопросу в главе 7:

Если вам нужно передать несколько элементов в аргументе, вы можете связать их в единую структуру данных и передать указатель бросание на неподписанный долго, безопасную практику на всех поддерживаемых архитектурах и довольно частое управление памятью (как описано в главе 15).

В этом ядре есть много примеров, см., Например, s_err_report timer в модуле файловой системы ext4. Указатель на struct super_block передается функции таймера с листами до unsigned long и обратно, как описано выше.

+0

Инструктивный ответ. Просмотрев существующий пример из ядра, что-то меня поражает: в присваивании указателя нет окружения '# ifdef'. Таким образом, если 'long' не _enough_, чтобы безопасно отображать указатель, это приведет к неопределенному поведению позже (в худшем случае) или предотвратит компиляцию, если -Werror установлен (в лучшем случае). Таким образом, архитектура, не обеспечивающая выравнивание по размеру, не может иметь надежную поддержку ext4? – Rerito

+1

Если я не ошибаюсь, для каждой архитектуры, поддерживаемой ядром, 'sizeof (unsigned long)' такой же, как 'sizeof (void *)' для кода, запущенного в режиме ядра. Приложения с пользовательским режимом - это еще одна история, там могут применяться различные правила. Существует интересное сравнение размеров различных типов данных на десятке архитектур в главе 11 книги «Linux Driver Development», которую я цитировал ранее. – Eugene

+1

Еще одна цитата из этой главы 11, в которой это явно указано. «Следовательно, общие адреса памяти в ядре обычно беззнаковые долго, используя тот факт, что указатели и длинные целые числа всегда имеют одинаковый размер, по крайней мере, на всех платформах, которые в настоящее время поддерживаются Linux». – Eugene

Смежные вопросы