Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
- Название:Разработка приложений в среде Linux. Второе издание
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:2007
- Город:Москва
- ISBN:978-5-8459-1143-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Майкл Джонсон - Разработка приложений в среде Linux. Второе издание краткое содержание
Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет собой отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из других операционных систем. Подробно рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование свободно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Изобилие хорошо документированных примеров кода помогает лучше усвоить особенности программирования в Linux.
Книга рассчитана на разработчиков разной квалификации, а также может быть полезна для студентов и преподавателей соответствующих специальностей.
Разработка приложений в среде Linux. Второе издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
2:
3: #include
4: #include
5: #include
6: #include
7: #include
8: #include
9: #include
10: #include
11: #include
12: #include
13:
14: #include
15:
16: int gotAlarm;
17:
18: void catch(int sig) {
19: gotAlarm = 1;
20: }
21:
22: #define OFFSET 10
23:
24: int main(int argc, const char ** argv) {
25: int pipeFds[2];
26: int count;
27: int numFds;
28: struct pollfd * pollFds;
29: struct epoll_event event;
30: int epfd;
31: int i;
32: struct rlimit lim;
33: char * end;
34:
35: if (!argv[1]) {
36: fprintf(stderr, "ожидалось число\n");
37: return 1;
38: }
39:
40: numFds = strtol(argv[1], &end, 0);
41: if (*end) {
42: fprintf(stderr, "ожидалось число\n");
43: return 1;
44: }
45:
46: printf("Запуск теста для %d файловых дескрипторов.\n", numFds);
47:
48: lim.rlim_cur = numFds + OFFSET;
49: lim.rlim_max = numFds + OFFSET;
50: if (setrlimit(RLIMIT_NOFILE, &lim)) {
51: perror("setrlimit");
52: exit(1);
53: }
54:
55: pipe(pipeFds);
56:
57: pollFds = malloc(sizeof (*pollFds) * numFds);
58:
59: epfd = epoll_create(numFds);
60: event.events = EPOLLIN;
61:
62: for (i = OFFSET; i < OFFSET + numFds; i++) {
63: if (dup2(pipeFds[0], i) != i) {
64: printf("сбой в %d: %s\n", i, strerror(errno));
65: exit(1);
66: }
67:
68: pollFds[i - OFFSET].fd = i;
69: pollFds[i - OFFSET].events = POLLIN;
70:
71: event.data.fd = i;
72: epoll_ctl(epfd, EPOLL_CTL_ADD, i, &event);
73: }
74:
75: /* с помощью signal выяснить, когда время истекло */
76: signal(SIGALRM, catch);
77:
78: count = 0;
79: gotAlarm = 0;
80: alarm(1);
81: while (!gotAlarm) {
82: poll(pollFds, numFds, 0);
83: count++;
84: }
85:
86: printf("Вызовов poll() в секунду: %d\n", count);
87:
88: alarm(1);
89:
90: count = 0;
91: gotAlarm = 0;
92: alarm(1);
93: while (!gotAlarm) {
94: epoll_wait(epfd, &event, 1, 0);
95: count++;
96: }
97:
98: printf("Вызовов epoll() в секунду: %d\n", count);
99:
100: return 0;
101: }
13.2. Отображение в памяти
Операционная система Linux позволяет процессу отображать файлы в их адресное пространство. Такое отображение создает взаимно однозначное соответствие между данными в файле и в отображаемой области памяти. Отображение в памяти обладает рядом преимуществ.
Высокоскоростной доступ к файлам. Нормальные механизмы ввода-вывода, такие как read()
и write()
, вынуждают ядро копировать данные через буфер ядра, а не непосредственно между файлом, содержащим устройство, и процессом пространства пользователя. Карты памяти устраняют этот промежуточный буфер, сохраняя копию памяти [84] Сохранение копии памяти может показаться не столь важным, но благодаря эффективному механизму кэширования Linux, эти задержки копий являются самой медленной частью записи в файлы данных, в которых нет набора O_SYNC .
.
Исполняемые файлы можно отображать на память программы, позволяя программе динамически загружать новые исполняемые области. Именно так реализуется динамическая загрузка, описанная в главе 27.
Новую память можно распределить отображением части /dev/zero
, специального устройства, состоящего из нулей [85] Хотя большинство устройств символьного ввода-вывода не могут быть отображены, /dev/zero отображается именно для этого типа приложений.
, или же через анонимное отображение. Средство Electric Fence, описанное в главе 7, использует этот механизм для распределения памяти.
Новую память, распределенную посредством карт памяти, можно сделать исполняемой, наполняя ее машинными командами, которые затем запускаются. Это свойство используется оперативными (just-in-time) компиляторами.
Файлы могут рассматриваться как память и читаться с использованием указателей, а не системных вызовов. Это существенно упрощает программы, избавляя от необходимости применения вызовов read()
, write()
и seek()
.
Отображение в памяти позволяет процессам совместно использовать области памяти, участвующие в создании и уничтожении процесса. Содержимое памяти хранится в отображаемом файле, делая его независимым от процессов.
13.2.1. Выравнивание по страницам
Системная память делится на порции под названием страницы. Размер страницы изменяется в зависимости от архитектуры, и на некоторых процессорах размер страницы может изменяться ядром. Функция getpagesize()
возвращает размер (в байтах) каждой страницы системы.
#include
size_t getpagesize(void);
Для каждой страницы системы ядро сообщает оборудованию, каким образом каждый процесс может получить доступ к странице (например, записать, выполнить или не выполнять никаких действий). Когда процесс пытается получить доступ к странице способом, нарушающим ограничения ядра, это вызывает ошибку сегментации ( SIGSEGV
), которая обычно приводит к завершению процесса.
Адрес памяти должен быть выровнен по страницам, если это адрес начала страницы. Иначе говоря, адрес должен быть целым, кратным размеру страницы архитектуры. В системе со страницами в 4 Кбайт адреса 0, 4 096, 16 384 и 32 768 являются выровненными по страницам (конечно, это далеко не весь список), потому что первая, вторая, пятая и девятая страницы системы начинаются с указанных адресов.
13.2.2. Установка отображения в памяти
Новые карты памяти создаются с помощью системного вызова mmap()
.
#include
caddr_tmmap(caddr_t address, size_t length , int protection, int flags,
int fd, off_t offset);
Параметр address
указывает, где именно в памяти необходимо отображать данные. Обычно address
— это NULL
, который означает, что для процесса не имеет значения местонахождение новой карты, и позволяет ядру выбрать любой адрес. Если адрес указан, он должен быть выровнен по страницам и в данный момент не использоваться. Если запрашиваемая карта будет конфликтовать с другой картой или не будет выровнена по страницам, mmap()
может дать сбой.
Второй параметр, length
, сообщает ядру, какую часть файлов следует отображать в памяти. Можно успешно отобразить больше памяти, чем количество данных в наличии у файла, но попытка доступа к нему может привести к SIGSEGV
[86] Ошибка сегментации возникнет при попытке доступа к нераспределенной странице.
.
Процесс проверяет, какие типы доступа разрешены новой области памяти. Это должно быть одно или несколько значений из табл. 13.2, объединенных с помощью битового "ИЛИ", либо PROT_NONE
, если доступ к отображаемой области запрещен. Файл может отображаться только для типов доступа, которые также были запрошены при изначальном открытии файла. Например, файл, открытый как O_RDONLY,
не может быть отображен для записи с помощью PROT_WRITE
.
Интервал:
Закладка: