|
newlib stdio, перенаправление ввода/вывода |
|
|
|
Nov 4 2010, 13:18
|

Участник

Группа: Участник
Сообщений: 71
Регистрация: 24-02-08
Из: Москва
Пользователь №: 35 348

|
Цитата(Сергей Борщ @ Nov 4 2010, 15:39)  Посмотрите setvbuf(); Цитата(Petka @ Nov 4 2010, 16:00)  newlib - достаточно "взрослая" библиотека. Для увеличения производительности она буферизует вывод, в том числе и на stdout (насколько я помню stderr не буферизуется для удобства отладки). Содержимое буфера скидывается либо по fflush как было сказано выше, либо по символу перевода строки "\r\n". По поводу yagartoo - она уже давно умела нормально собирать данный функционал. Благодарю, уже почитал маны по теме. Не ожидал, что embedded библиотека столь "достаточно "взрослая"".
|
|
|
|
|
Nov 6 2010, 20:36
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(Spym @ Nov 3 2010, 19:53)  Из первого вызова printf вызывается __sinit, где происходит инициализация stdout/stdin/stderr. Вот этот момент мне не очень понятен. Чем инициализируется stdout? Иными словами, куда, на какое устройство будут выводиться данные, отправляемые в stdout? У меня типичная инициализация происходит так (упрощенный пример - сервер, принимающий tcp соединения): Код ..... int s = socket(.....); listen(s, .....); ..... int sd = accept(s); // получили дескриптор нового tcp соединения stdin = stdout = stderr = fdopen(sd, "w+"); ............. printf("Hello!\n"); В результате вызова printf() я получаю вызов _write(int, char*, int), первым аргументом которого будет значение sd, указанное при вызове fdopen(). А что я получу в качестве первого аргумента _write, если не сделаю fdopen? Как в этом случае _write должна решить, куда отправлять данные, на которые указывает второй аргумент?...
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 7 2010, 04:55
|

Участник

Группа: Участник
Сообщений: 71
Регистрация: 24-02-08
Из: Москва
Пользователь №: 35 348

|
Цитата(alx2 @ Nov 6 2010, 23:36)  Вот этот момент мне не очень понятен. Чем инициализируется stdout? Как я уже писал, на момент входа в main дескрипторы для stdin/stdout/stderr уже существуют, и инициализируются при первом обращении при помощи __sinit. Цитата(alx2 @ Nov 6 2010, 23:36)  В результате вызова printf() я получаю вызов _write(int, char*, int), первым аргументом которого будет значение sd, указанное при вызове fdopen(). А что я получу в качестве первого аргумента _write, если не сделаю fdopen? Как в этом случае _write должна решить, куда отправлять данные, на которые указывает второй аргумент?... В случае newlib, вы получите дескриптор _reent->_stdin (ну или _stdout, _stderr) (посмотрите в newlib: sys/reent.h) - это позволит принять решение о целевом устройстве.
|
|
|
|
|
Nov 7 2010, 20:53
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(Spym @ Nov 7 2010, 09:55)  Как я уже писал, на момент входа в main дескрипторы для stdin/stdout/stderr уже существуют, и инициализируются при первом обращении при помощи __sinit. В случае newlib, вы получите дескриптор _reent->_stdin (ну или _stdout, _stderr) (посмотрите в newlib: sys/reent.h) - это позволит принять решение о целевом устройстве. Не могу с Вами полностью согласиться. Стандартные потоки, безусловно, существуют, как некий объект в памяти. Вопрос был в том, можно ли начать работать с этими объектами, предварительно явно их не инициализировав. О том, что они автоматически инициализируются при первом обращении, я не знал, спасибо за информацию. Мысль же моя заключалась в том, что для последующей работы с выводом на низком уровне (в соответствующих системных вызовах) необходимо, чтобы этим системным вызовам передавались осмысленные аргументы и, в частности, файловый дескриптор. При явной инициализации потока (через fopen или fdopen) это осмысленное значение предоставляет программист. А если инициализация происходит "автомагически", без участия программиста, откуда тогда возьмется это осмысленное значение? Вот сейчас я посмотрел код newlib. Значение дескриптора хранится в поле _file структуры FILE. То есть системным вызовам, в нашем случае _write(), в качестве первого аргумента передается _reent->_stdout->_file. Теперь смотрим, какое же значение там находится. __sinit() для инициализации стандартных потоков вызывает __sfp(), которая, в свою очередь, инициализирует поле _file значением -1. Таким образом, при выполнении каких-либо операций с таким потоком системным вызовам будет передаваться -1 в качсетве файлового дескриптора, что традиционно означает невалидный дескриптор, и такой системный вызов, как правило, должен давать ошибку EBADF (bad file descriptor). По крайней мере, никакого решения о целевом устройстве такой дескриптор принять не позволит. Конечно, если в целевой системе заведомо существует только одно устройство ввода/вывода (например один com-порт), тогда все операции производятся с ним и только с ним, и можно, наверное, в системных вызовах не анализировать значение дескриптора. Но как только мы допускаем наличия нескольких логических устройств (хотя бы двух com-портов), возникает и необходимость мультиплексировать операции ввода/вывода, а для этого потребуется селектор, которым и является дескриптор, передаваемый первым аргументом. И тогда придется-таки открывать потоки явно через fopen(3)/fdopen(3)...
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 8 2010, 08:03
|

Участник

Группа: Участник
Сообщений: 71
Регистрация: 24-02-08
Из: Москва
Пользователь №: 35 348

|
Цитата(alx2 @ Nov 7 2010, 23:53)  Не могу с Вами полностью согласиться. Подозреваю, что мы говорим о различных версиях newlib; у меня 1.18, как я уже писал тут. Цитата(alx2 @ Nov 7 2010, 23:53)  если инициализация происходит "автомагически", без участия программиста, откуда тогда возьмется это осмысленное значение? В случае 1.18, значение возмется из machine/spu/c99ppe.h: Код #define SPE_STDIN 1 #define SPE_STDOUT 2 #define SPE_STDERR 3 Цитата(alx2 @ Nov 7 2010, 23:53)  __sinit() для инициализации стандартных потоков вызывает __sfp(), которая, в свою очередь, инициализирует поле _file значением -1. Для 1.18 это не совсем верно: Код _VOID _DEFUN (__sinit, (s), struct _reent *s) { s->__cleanup = __cleanup; s->__sdidinit = 1;
s->_stdin = &s->__sf[0]; s->_stdin->_fp = SPE_STDIN;
s->_stdout = &s->__sf[1]; s->_stdout->_fp = SPE_STDOUT;
s->_stderr = &s->__sf[2]; s->_stderr->_fp = SPE_STDERR; } Соответственно, для stdin/stdout/stderr мы получим дескрипторы 1, 2, 3.
|
|
|
|
|
Nov 9 2010, 07:14
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
А, понял. Вы говорите о __sinit из newlib/libc/machine/spu/stdio.c, а я смотрел __sinit() из newlib/libc/stdio/findfp.c. У меня (вот сейчас смотрю map-файл реального проекта) используется __sinit именно из findfp.o (arm-elf/lib/libc.a). А у Вас не так? Цитата(Spym @ Nov 8 2010, 13:03)  Соответственно, для stdin/stdout/stderr мы получим дескрипторы 1, 2, 3. Вы говорите о различиях стандартных потоков ввода, вывода и ошибок. Я говорил о другом. Допустим, в целевом устройстве два com-порта. Для работы с ними я запускаю две одинаковые задачи. В каждой из них выполняется printf(), то есть производится вывод в stdout. Но одна задача должна выводить в один com-порт, другая - в другой! Для этого каждая задача должна по-своему проинициализировать stdout. Если первая задача выполнит stdout = fdopen(1, "w+"); а вторая - stdout = fdopen(2, "w+");, то printf(...) из первой задачи даст вызов _write(1, ....), а из второй - _write(2, .....).
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 9 2010, 09:17
|

Участник

Группа: Участник
Сообщений: 71
Регистрация: 24-02-08
Из: Москва
Пользователь №: 35 348

|
Вы не ответили, какую версию newlib используете. Цитата(alx2 @ Nov 9 2010, 10:14)  Вы говорите о различиях стандартных потоков ввода, вывода и ошибок. Я говорил о другом. Верно, я говорил о другом, априори полагая, что все таски должны всё-таки по-умолчанию использовать общий stdout.
|
|
|
|
|
Nov 10 2010, 06:24
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(Spym @ Nov 9 2010, 14:17)  Вы не ответили, какую версию newlib используете. А Вы не спрашивали.  Вы лишь высказали предположение, что мы говорим о разных версиях... Нет, я говорю о newlib-1.18.0.
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 10 2010, 10:00
|

Участник

Группа: Участник
Сообщений: 71
Регистрация: 24-02-08
Из: Москва
Пользователь №: 35 348

|
Цитата(alx2 @ Nov 10 2010, 09:24)  А Вы не спрашивали.  Точно - я вопрос забыл написать, но он подразумевался.  Ну и наконец, значения дескрипторов при выполнении: Цитата "_impure_ptr->_stdin->_file" short int 0 short int "_impure_ptr->_stdout->_file" short int 1 short int "_impure_ptr->_stderr->_file" short int 2 short int Хм.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|