URL: https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 6596
[ Назад ]

Исходное сообщение
"Kernel: Device driver: System call: Incorrect ThreadID"

Отправлено Lion , 10-Июл-07 20:18 
ОС: FreeBSD 6.2
Есть такая задача:
Узнать ID потока (не процеса PID а имено потока TreadID) в модуле ядра. Тоесть в функциях open, read, write, ioct и т.д.

Вот пример:
Есть две потока каждый вызивает к примеру ioct моего модуля там же я вывожу TreadID. Беру его я из структуры struct thread *td, которая передаеться параметром в мою функцию обработчика системного вызова ioctl. Вместо нее можно исполльзовать глобальну переменную curthread что есть еквиваленьным.

test.c
///Test thread
int h;

void *routine(void *arg)
{
    char buf[127];
    ioctl(h, STATUS, &buf);
    return NULL;
}

///Test main function
int main()
{
    pthread_t threadID1;
    pthread_t threadID2;
    h = open("/dev/mydev", O_RDWR);
    if (h < 0)
        return -1;
    pthread_create(&threadID1, NULL, &routine, NULL);
    pthread_create(&threadID2, NULL, &routine, NULL);

    sleep(10);
    close(h);

    return 0;
}

driver.c
///Device driver
int can_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
{
   ....
   printf("ThreadID=%d\n", td->td_tid);
   // or printf("ThreadID=%d\n", curthread->td_tid);
   ....
}

Но td/curthread имееют одинаковые адреса, сотвествено и значения поля td_tid (как вияснл експеремнтальным путем оно соответсвует ID главного (main()) потока процес).! Почему?
Причем если делать какие небуть действия (доступ к апаратуре и.т.д) в iotcl. Тогда эты значение начинають отличаться :(
Потоки уже и порождал с задержкой друг от друга, и засускал в разное время, ничегон е меняеться. Уже замахался исходжники ядра парсать :) что узнать причниу или хотябы как формируеться параметр struct thread *td. Пытался синхронизировать  и спин мютексом и Giant. Без результатно.

Кто небуть обяснить может в чем причина?


Содержание

Сообщения в этом обсуждении
"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено int _0dh , 11-Июл-07 21:03 
>ОС: FreeBSD 6.2
>Есть такая задача:
>Узнать ID потока (не процеса PID а имено потока TreadID) в модуле
>ядра. Тоесть в функциях open, read, write, ioct и т.д.
>
>Вот пример:
>Есть две потока каждый вызивает к примеру ioct моего модуля там же
>я вывожу TreadID. Беру его я из структуры struct thread *td,
>которая передаеться параметром в мою функцию обработчика системного вызова ioctl. Вместо
>нее можно исполльзовать глобальну переменную curthread что есть еквиваленьным.
>
>test.c
>///Test thread
>int h;
>
>void *routine(void *arg)
>{
>    char buf[127];
>    ioctl(h, STATUS, &buf);
>    return NULL;
>}
>
>///Test main function
>int main()
>{
>    pthread_t threadID1;
>    pthread_t threadID2;
>    h = open("/dev/mydev", O_RDWR);
>    if (h < 0)
>        return -1;
>    pthread_create(&threadID1, NULL, &routine, NULL);
>    pthread_create(&threadID2, NULL, &routine, NULL);
>
>    sleep(10);
>    close(h);
>
>    return 0;
>}
>
>driver.c
>///Device driver
>int can_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread
>*td)
>{
>   ....
>   printf("ThreadID=%d\n", td->td_tid);
>   // or printf("ThreadID=%d\n", curthread->td_tid);
>   ....
>}
>
>Но td/curthread имееют одинаковые адреса, сотвествено и значения поля td_tid (как вияснл
>експеремнтальным путем оно соответсвует ID главного (main()) потока процес).! Почему?
>Причем если делать какие небуть действия (доступ к апаратуре и.т.д) в iotcl.
>Тогда эты значение начинають отличаться :(
>Потоки уже и порождал с задержкой друг от друга, и засускал в
>разное время, ничегон е меняеться. Уже замахался исходжники ядра парсать :)
>что узнать причниу или хотябы как формируеться параметр struct thread *td.
>Пытался синхронизировать  и спин мютексом и Giant. Без результатно.
>
>Кто небуть обяснить может в чем причина?
Хм, а что возвращает ioctl() потокам? и какой при этом errno?


"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено Lion , 12-Июл-07 11:47 
>Хм, а что возвращает ioctl() потокам? и какой при этом errno?
Она возращает по такому принципу, то что возвращает моя функция (или обработчик симстемного вызова ioctl) как раз  и являються на сторонепользователься переменной errno. Другими словами:
Kernel:         User:
return 0;       errno = 0,   ioctl() = 0;
return err;     errno = err, ioctl() = -1;

Где err есть любое значение из набора значений errno (man errno). Например: ENOENT, ENXIO и т.д. В моем примере она возращает "0". Думаю что это никак не влияет на параметры которые передаються функции они же не немогу зависить от результата функции. (Нельяз пригнуть в будущее и изминить прошлое :) )


"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено Lion_Ua , 12-Июл-07 14:17 
И еще есть подазрение, точнее практически я это увидел что не срабативает спин блокировка да и простая mutex синхронизация!  Все инициализирую как надо а оно не работать Или я спин локировка работает по другому? :(. Может кто подскажет что еще за Giant локировка така (глобальная переменная ядра Giant)?. Если б не розсинхронизация я б не узнал об проблема с потоками (первый пост)

"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено int _0dh , 12-Июл-07 18:31 
>И еще есть подазрение, точнее практически я это увидел что не срабативает
>спин блокировка да и простая mutex синхронизация!  Все инициализирую как
>надо а оно не работать Или я спин локировка работает по
>другому? :(. Может кто подскажет что еще за Giant локировка така
>(глобальная переменная ядра Giant)?. Если б не розсинхронизация я б не
>узнал об проблема с потоками (первый пост)
Мне просто пришло в голову, что возможно имеется некий поточный менеджер в libc, соответсно каждый поток выполняется в контексте этого поточного менеджера => из ядра это будет видно как будто бы 2 потока - это 1 main поток. Я возможно немножко путанно обьясняю :)
Другимим словами в многопоточной программе имеется что-то вроде
_start: // это точка входа процесса
...
call __init_thread_dispatcher
call __init_other_runtime
...
//prepare arguments for main
push ret_code
call main
..
а всякие pthread_create/destroy etc - это вызовы этого thread manager, шедулинг потоков выполняет он и зашедуленный поток выполняется в его контексте

Все вышенаписанное - исключительно мои фантазии, навеяные неумеренным потреблением стимуляторов :)


"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено vic , 12-Июл-07 18:44 
>>И еще есть подазрение, точнее практически я это увидел что не срабативает
>>спин блокировка да и простая mutex синхронизация!  Все инициализирую как
>>надо а оно не работать Или я спин локировка работает по
>>другому? :(. Может кто подскажет что еще за Giant локировка така
>>(глобальная переменная ядра Giant)?. Если б не розсинхронизация я б не
>>узнал об проблема с потоками (первый пост)
>Мне просто пришло в голову, что возможно имеется некий поточный менеджер в libc, соответсно каждый поток выполняется в контексте этого поточного менеджера => из ядра это будет видно как будто бы 2 потока - это 1 main поток. Я возможно немножко путанно обьясняю :)
>Другимим словами в многопоточной программе имеется что-то вроде
>_start: // это точка входа процесса
>...
>call __init_thread_dispatcher
>call __init_other_runtime
>...
>//prepare arguments for main
>push ret_code
>call main
>..
>а всякие pthread_create/destroy etc - это вызовы этого thread manager, шедулинг потоков
>выполняет он и зашедуленный поток выполняется в его контексте
>
>Все вышенаписанное - исключительно мои фантазии, навеяные неумеренным потреблением стимуляторов :)

ну не такие уж и фантизии.. user threads, kernel threads, LWP..
http://sysoev.ru/prog/kse.html тут к примеру.


"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено Lion_Ua , 12-Июл-07 19:51 
>ну не такие уж и фантизии.. user threads, kernel threads, LWP..
>http://sysoev.ru/prog/kse.html тут к примеру.

Все конечно хорошо (статью я еще поковыряю детальный). Но повторюсь если сделать задрежку в драйвере тогда ID уже разные. Причем если из под gdb смотреть то потоки имеють различный LWP
и вот что интересно:

(gdb) info threads
[New Thread 0x8053600 (sleeping)]
[New Thread 0x8053400 (sleeping)]
[New Thread 0x8053200 (LWP 100079)]
  5 Thread 0x8053200 (LWP 100079)  0x28091277 in pthread_testcancel () from /usr/lib/libpthread.so.2
  4 Thread 0x8053400 (sleeping)  0x28089e7f in pthread_mutexattr_init () from /usr/lib/libpthread.so.2
  3 Thread 0x8053600 (sleeping)  0x28089e7f in pthread_mutexattr_init () from /usr/lib/libpthread.so.2
* 2 Thread 0x8053000 (LWP 100097)  main () at main_cdev.cpp:61

LWP или имеет значение числовое (которе похоже на то что вытягиваю как ThreadID) или sleeping. Полностю уверен что система надает единственый интерефейс для работы с потоками а POSIX есть лиш врапером для того чтоб достичь некоторого уровня переносимости. Я не думаю что библиотека pthread придумала еще свои какието виртуальные поток(и) и ими управляет. Зачем тогда в модуле ядра придумали такое понятие как struct thread *td (или curthread) если для него из стороны пользователя будет всегда один поток на один процес! тогда полностю нерально реализировать блокировку потокв пользователя таким образом. Так как в таком случае ушол бы спать главный (как бы тот кто из pthread управлет всеми) поток, а соответсвено и все други его подчиненные.
Есть конечно выход как идентифицировать поток юзера, это указатель на него (или структуру управления) либо значение функции phthread_self() но это всего лиш абстрактный тип pthread_t как идинтификатор или гендлер потока для библиотеки pthread. Пока что он типа int. Но это пока и в будущем может стать структурой так что это не совсем подходит разве что для даного промежутка времени. Да и чоб как то использовать это значение надо его передать в драйвер тоесть всегда за собой таскать штучно при вызове read, write или ioctl что не есть гуд. Уже замахался исходники ядра бровзать :)

Проблемка пока остаеться открытой :(


"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено int _0dh , 12-Июл-07 20:40 
>>ну не такие уж и фантизии.. user threads, kernel threads, LWP..
>>http://sysoev.ru/prog/kse.html тут к примеру.
>
>Все конечно хорошо (статью я еще поковыряю детальный). Но повторюсь если сделать
>задрежку в драйвере тогда ID уже разные.
а как вы делаете задержку и как вы узнаете что они разные? что-то типа такого:
int my_ioctl(...) {
  cprintf("TID before waiting %ld\n", currtptr->tid);
  WAIT;
  cprintf("TID after waiting %ld\n", currtptr->tid);
  ....
} и значения до и после отличаются?

Я просто хотел сказать что поток в процессе пользователя имеет в общем случае весьма косвенное отношение к curthread. Если вызов ioctl() вытесняемый то может быть имеет смысл выключить preemption на время вызова для грубого решения вашей проблемы ? К сожалению я ни коим образом не являюсь знатоком ядра FreeBSD : (.

Причем если из под
>gdb смотреть то потоки имеють различный LWP
>и вот что интересно:
>
>(gdb) info threads
>[New Thread 0x8053600 (sleeping)]
>[New Thread 0x8053400 (sleeping)]
>[New Thread 0x8053200 (LWP 100079)]
>  5 Thread 0x8053200 (LWP 100079)  0x28091277 in pthread_testcancel ()
>from /usr/lib/libpthread.so.2
>  4 Thread 0x8053400 (sleeping)  0x28089e7f in pthread_mutexattr_init () from
>/usr/lib/libpthread.so.2
>  3 Thread 0x8053600 (sleeping)  0x28089e7f in pthread_mutexattr_init () from
>/usr/lib/libpthread.so.2
>* 2 Thread 0x8053000 (LWP 100097)  main () at main_cdev.cpp:61
>
>LWP или имеет значение числовое (которе похоже на то что вытягиваю как
>ThreadID) или sleeping. Полностю уверен что система надает единственый интерефейс для
>работы с потоками а POSIX есть лиш врапером для того чтоб
>достичь некоторого уровня переносимости. Я не думаю что библиотека pthread придумала
>еще свои какието виртуальные поток(и) и ими управляет. Зачем тогда в
>модуле ядра придумали такое понятие как struct thread *td (или curthread)
>если для него из стороны пользователя будет всегда один поток на
>один процес! тогда полностю нерально реализировать блокировку потокв пользователя таким образом.
Почему не реально? вполне реально имхо. например в случае захвата блокировки код ядра может сделать что-то вроде longjmp в контекст юзерского шедулера потоков.
>Так как в таком случае ушол бы спать главный (как бы
>тот кто из pthread управлет всеми) поток, а соответсвено и все
>други его подчиненные.
>Есть конечно выход как идентифицировать поток юзера, это указатель на него (или
>структуру управления) либо значение функции phthread_self() но это всего лиш абстрактный
>тип pthread_t как идинтификатор или гендлер потока для библиотеки pthread. Пока
>что он типа int. Но это пока и в будущем может
>стать структурой так что это не совсем подходит разве что для
>даного промежутка времени. Да и чоб как то использовать это значение
>надо его передать в драйвер тоесть всегда за собой таскать штучно
>при вызове read, write или ioctl что не есть гуд. Уже
>замахался исходники ядра бровзать :)
>
>Проблемка пока остаеться открытой :(



"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено Lion_Ua , 13-Июл-07 12:08 
>а как вы делаете задержку и как вы узнаете что они разные?
>что-то типа такого:
>int my_ioctl(...) {
>  cprintf("TID before waiting %ld\n", currtptr->tid);
>  WAIT;
>  cprintf("TID after waiting %ld\n", currtptr->tid);
>  ....
>} и значения до и после отличаются?
>
>Я просто хотел сказать что поток в процессе пользователя имеет в общем
>случае весьма косвенное отношение к curthread. Если вызов ioctl() вытесняемый то
>может быть имеет смысл выключить preemption на время вызова для грубого
>решения вашей проблемы ? К сожалению я ни коим образом не
>являюсь знатоком ядра FreeBSD : (.

Я также не очень знаток но приходиться работать с ядром. Что такое preemption  :) ?
Да задержку почти так и дела, только я сравнивал не до и после, я ставил просто перед началом задержку и выводил значение, и тут то оно и было разное, для разних потоков. Только мне кажеться что если тут все так преплетаеться: юзер сриды, кернел сриды, обекты которые представляют эти сриды и.т.д, то можно допусить что нельзя 100% идентифицировать даным методом поток пользователя (или даже кренел срид также) :( обидно. Хотя давно ходит мнение не испльзовать сриды и юзать потоки, что есть более надежным да и пиды их точно идеднтифицируют процес однозначно :). Но как то очень уж грубо выглядит это тем более если надо использовать общии ресурсы! Полкучиться очень моного комуникаций и связей между процесами лиш только чтоб доступиться один к другом для внутреных нужд. Связей между обектами должно быть миниму!

Если есть еще идеи теории предложение рад буду выслушать. :)


"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено int _0dh , 13-Июл-07 12:31 
>>а как вы делаете задержку и как вы узнаете что они разные?
>>что-то типа такого:
>>int my_ioctl(...) {
>>  cprintf("TID before waiting %ld\n", currtptr->tid);
>>  WAIT;
>>  cprintf("TID after waiting %ld\n", currtptr->tid);
>>  ....
>>} и значения до и после отличаются?
>>
>>Я просто хотел сказать что поток в процессе пользователя имеет в общем
>>случае весьма косвенное отношение к curthread. Если вызов ioctl() вытесняемый то
>>может быть имеет смысл выключить preemption на время вызова для грубого
>>решения вашей проблемы ? К сожалению я ни коим образом не
>>являюсь знатоком ядра FreeBSD : (.
>
>Я также не очень знаток но приходиться работать с ядром. Что такое
>preemption  :) ?
>Да задержку почти так и дела, только я сравнивал не до и
>после, я ставил просто перед началом задержку и выводил значение, и
>тут то оно и было разное, для разних потоков. Только мне
>кажеться что если тут все так преплетаеться: юзер сриды, кернел сриды,
>обекты которые представляют эти сриды и.т.д, то можно допусить что нельзя
>100% идентифицировать даным методом поток пользователя (или даже кренел срид также)
>:( обидно. Хотя давно ходит мнение не испльзовать сриды и юзать
>потоки, что есть более надежным да и пиды их точно идеднтифицируют
>процес однозначно :). Но как то очень уж грубо выглядит это
>тем более если надо использовать общии ресурсы! Полкучиться очень моного комуникаций
>и связей между процесами лиш только чтоб доступиться один к другом
>для внутреных нужд. Связей между обектами должно быть миниму!
>
>Если есть еще идеи теории предложение рад буду выслушать. :)
preemption - это вытеснение. Т.е когды один поток заснул в ващем ioctl(), он возможно может быть вытеснен
другим потоком, который тоже сделает ваш ioctl().
А почему бы не радикально не перенести синхронизацию в user level? :)

"Kernel: Device driver: System call: Incorrect ThreadID"
Отправлено Lion_Ua , 13-Июл-07 17:00 
>preemption - это вытеснение. Т.е когды один поток заснул в ващем ioctl(),
>он возможно может быть вытеснен
>другим потоком, который тоже сделает ваш ioctl().
>А почему бы не радикально не перенести синхронизацию в user level? :)

1. Синхронизировать надо так как доступ к паратауре очень критичен, если кто (а таких много :)) не будет синхорниировать и в драйвере тоже, тогда может подвичнуть вся система из за одоновременно доступа к паратуре! Єто надо защищать поюбому но для єто надо юзать спін локировку mtx_lock_spin. Котора кстати не совсем работает почему то у меня и это вторая часть вопроса.
2. Мне надо было просто идентифицировать юзерський поток для того чтоб испольщовать ето как идентификатор данных так как мне надо обратную связь. Короче так:
   Несколько сридов кидают пакет на отправку.
   Они все помещаються в очередь и потоки засыпают до того момента когда имено их пакет будет отправлен или нет (ошибка отправки)
   Когда срабативает переривание что железяка отправила пакет все просипаються и проверяют их ли пакет бы отправлен. И т.д. Вот имено срид ID как не кстати подошол бы мне.:) Или какой то уникальный ID пакета но вешать задачу на пользователя генерить уникальные ID не хотелось б что б он просто кинуть пакет и ждать ответа.
Есть кончено агресивынй метод убрать очередь на отправку :) И залочить полностю функцию тогда тольо один поток будет владеть функцией и сразу же получит ответ :) Синхронный ввод вывод. А  хотел асинхронный с обратной связю :)