ОС: 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. Без результатно.Кто небуть обяснить может в чем причина?
>ОС: 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?
>Хм, а что возвращает 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". Думаю что это никак не влияет на параметры которые передаються функции они же не немогу зависить от результата функции. (Нельяз пригнуть в будущее и изминить прошлое :) )
И еще есть подазрение, точнее практически я это увидел что не срабативает спин блокировка да и простая mutex синхронизация! Все инициализирую как надо а оно не работать Или я спин локировка работает по другому? :(. Может кто подскажет что еще за Giant локировка така (глобальная переменная ядра Giant)?. Если б не розсинхронизация я б не узнал об проблема с потоками (первый пост)
>И еще есть подазрение, точнее практически я это увидел что не срабативает
>спин блокировка да и простая 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, шедулинг потоков выполняет он и зашедуленный поток выполняется в его контекстеВсе вышенаписанное - исключительно мои фантазии, навеяные неумеренным потреблением стимуляторов :)
>>И еще есть подазрение, точнее практически я это увидел что не срабативает
>>спин блокировка да и простая 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 тут к примеру.
>ну не такие уж и фантизии.. 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:61LWP или имеет значение числовое (которе похоже на то что вытягиваю как ThreadID) или sleeping. Полностю уверен что система надает единственый интерефейс для работы с потоками а POSIX есть лиш врапером для того чтоб достичь некоторого уровня переносимости. Я не думаю что библиотека pthread придумала еще свои какието виртуальные поток(и) и ими управляет. Зачем тогда в модуле ядра придумали такое понятие как struct thread *td (или curthread) если для него из стороны пользователя будет всегда один поток на один процес! тогда полностю нерально реализировать блокировку потокв пользователя таким образом. Так как в таком случае ушол бы спать главный (как бы тот кто из pthread управлет всеми) поток, а соответсвено и все други его подчиненные.
Есть конечно выход как идентифицировать поток юзера, это указатель на него (или структуру управления) либо значение функции phthread_self() но это всего лиш абстрактный тип pthread_t как идинтификатор или гендлер потока для библиотеки pthread. Пока что он типа int. Но это пока и в будущем может стать структурой так что это не совсем подходит разве что для даного промежутка времени. Да и чоб как то использовать это значение надо его передать в драйвер тоесть всегда за собой таскать штучно при вызове read, write или ioctl что не есть гуд. Уже замахался исходники ядра бровзать :)Проблемка пока остаеться открытой :(
>>ну не такие уж и фантизии.. 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 что не есть гуд. Уже
>замахался исходники ядра бровзать :)
>
>Проблемка пока остаеться открытой :(
>а как вы делаете задержку и как вы узнаете что они разные?
>что-то типа такого:
>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% идентифицировать даным методом поток пользователя (или даже кренел срид также) :( обидно. Хотя давно ходит мнение не испльзовать сриды и юзать потоки, что есть более надежным да и пиды их точно идеднтифицируют процес однозначно :). Но как то очень уж грубо выглядит это тем более если надо использовать общии ресурсы! Полкучиться очень моного комуникаций и связей между процесами лиш только чтоб доступиться один к другом для внутреных нужд. Связей между обектами должно быть миниму!Если есть еще идеи теории предложение рад буду выслушать. :)
>>а как вы делаете задержку и как вы узнаете что они разные?
>>что-то типа такого:
>>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? :)
>preemption - это вытеснение. Т.е когды один поток заснул в ващем ioctl(),
>он возможно может быть вытеснен
>другим потоком, который тоже сделает ваш ioctl().
>А почему бы не радикально не перенести синхронизацию в user level? :)1. Синхронизировать надо так как доступ к паратауре очень критичен, если кто (а таких много :)) не будет синхорниировать и в драйвере тоже, тогда может подвичнуть вся система из за одоновременно доступа к паратуре! Єто надо защищать поюбому но для єто надо юзать спін локировку mtx_lock_spin. Котора кстати не совсем работает почему то у меня и это вторая часть вопроса.
2. Мне надо было просто идентифицировать юзерський поток для того чтоб испольщовать ето как идентификатор данных так как мне надо обратную связь. Короче так:
Несколько сридов кидают пакет на отправку.
Они все помещаються в очередь и потоки засыпают до того момента когда имено их пакет будет отправлен или нет (ошибка отправки)
Когда срабативает переривание что железяка отправила пакет все просипаються и проверяют их ли пакет бы отправлен. И т.д. Вот имено срид ID как не кстати подошол бы мне.:) Или какой то уникальный ID пакета но вешать задачу на пользователя генерить уникальные ID не хотелось б что б он просто кинуть пакет и ждать ответа.
Есть кончено агресивынй метод убрать очередь на отправку :) И залочить полностю функцию тогда тольо один поток будет владеть функцией и сразу же получит ответ :) Синхронный ввод вывод. А хотел асинхронный с обратной связю :)