Мобильное программирование приложений реального времени в стандарте POSIX


size_t len, int prot, int


#include <sys/mman.h> void *mmap (void *addr, size_t len, int prot, int flags, int fildes, off_t off);
Листинг 5.1. Описание функции mmap().
Закрыть окно




#include <sys/mman.h> int mprotect (void *addr, size_t len, int prot);
Листинг 5.2. Описание функции mprotect().
Закрыть окно




#include <sys/mman.h> int munmap (void *addr, size_t len);
Листинг 5.3. Описание функции munmap().
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * * * */ /* Программа выдает на стандартный вывод файлы,*/ /* имена которых заданы в командной строке */ /* * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h>
int main (int argc, char *argv []) { struct stat sbuf; /* Структура для получения информации */ /* о файле */ int fd; /* Дескриптор обрабатываемого файла */ void *maddr; /* Адрес отображенного в память файла */ int i;


for (i = 1; i < argc; i++) { if ((fd = open (argv [i], O_RDONLY)) < 0) { perror ("OPEN"); continue; } if (fstat (fd, &sbuf) != 0) { perror ("FSTAT"); close (fd); continue; } if ((maddr = mmap (NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED){ perror ("MMAP"); close (fd); continue; } if (write (STDOUT_FILENO, maddr, sbuf.st_size) != sbuf.st_size) { perror ("WRITE"); } if (munmap (maddr, sbuf.st_size) != 0) { perror ("MUNMAP"); } close (fd); } /* for */
return 0; }
Листинг 5.4. Пример программы, использующей файлы, отображенные в память.
Закрыть окно




#include <unistd.h>
int truncate (const char *path, off_t length);
int ftruncate ( int fildes, off_t length);
Листинг 5.5. Описание функций truncate() и ftruncate.
Закрыть окно




#ifndef g_SHM #define g_SHM
/* Имя объекта в разделяемой памяти */ #define O_SHM_NAME "/g_o.shm"
/* Номер сигнала для синхронизации /* доступа к разделяемому сегменту */ #define SIG_SHM SIGALRM
#endif
Листинг 5.6. Заголовочный файл "g_shm.h" программы, копирующей строки со стандартного ввода на стандартный вывод.
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * */ /* Программа, состоящая из двух процессов, */ /* копирует строки со стандартного ввода на*/ /* стандартный вывод, используя в качестве */ /* буфера разделяемый сегмент, отображенный*/ /* в адресные пространства процессов. */ /* Для синхронизации доступа к разделяемому*/ /* сегменту используется сигнал SIGALRM */ /* * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h> #include <stdio.h> #include <signal.h> #include <sys/mman.h> #include <fcntl.h> #include <limits.h> #include <sys/wait.h> #include <assert.h>
#include "g_shm.h"
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Создание разделяемого сегмента памяти, */ /* отображение его в адресное пространство процесса, */ /* чтение строк со стандартного ввода в сегмент */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ int main (void) { int fd_shm; /* Дескриптор объекта в разделяемой памяти */ void *addr_shm; /* Адрес отображенного в память объекта */ sigset_t smask; /* Маска блокируемых сигналов */ siginfo_t sinfo;/* Структура для получения данных о сигнале */ /* Длительность ожидания прихода сигнала */ struct timespec stmspc = {10, 0}; pid_t cpid; /* Идентификатор порожденного процесса */
/* Создадим разделяемый сегмент памяти */ if ((fd_shm = shm_open (O_SHM_NAME, O_RDWR | O_CREAT, 0777)) < 0) { perror ("SHM_CREAT"); return (1); }
/* Сделаем размер созданного объекта равным LINE_MAX */ if (ftruncate (fd_shm, LINE_MAX) != 0) { perror ("FTRUNCATE"); return (2); }
/* Отобразим сегмент в память */ if ((addr_shm = mmap (NULL, LINE_MAX, PROT_READ | PROT_WRITE, MAP_SHARED, fd_shm, 0)) == MAP_FAILED) { perror ("MMAP-P"); return (3); }
/* Сформируем маску сигналов (блокируем SIG_SHM) */ (void) sigemptyset (&smask); (void) sigaddset (&smask, SIG_SHM); (void) sigprocmask (SIG_BLOCK, &smask, (sigset_t *) NULL);
/* Подготовительная работа закончена */
switch (cpid = fork ()) { case -1: perror ("FORK"); return (4); case 0: /* Чтение из объекта и выдачу на стандартный*/ /* вывод реализуем в порожденном процессе*/ if (execl ("./g_r_shm", "g_r_shm", ( char *) NULL) < 0) { perror ("EXECL"); return (5); } }
/* Чтение строк со стандартного ввода в объект */ /* возложим на родительский процесс. */ /* В начальный момент объект в разделяемой памяти */ /* доступен для записи*/ while (fgets (addr_shm, LINE_MAX, stdin) != NULL) { /* Сообщим порожденному процессу, */ /* что в объект в разделяемой памяти */ /* помещена очередная строка */ assert (kill (cpid, SIG_SHM) == 0); /* Дождемся, когда в объект можно будет прочитать*/ /* следующую строку */ if (sigtimedwait (&smask, &sinfo, &stmspc) != SIG_SHM) { break; } }
/* Порожденный процесс должен завершиться*/ /* по контролю времени ожидания*/ (void) wait (NULL);
if (shm_unlink (O_SHM_NAME) != 0) { perror ("SHM_UNLINK"); return (6); }
return (0); }
Листинг 5.7. Исходный текст начального процесса двухпроцессной программы, копирующей строки со стандартного ввода на стандартный вывод.
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Процесс берет строки из объекта в разделяемой памяти*/ /* и выдает их на стандартный вывод */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <unistd.h> #include <stdio.h> #include <signal.h> #include <sys/mman.h> #include <fcntl.h> #include <limits.h> #include <assert.h>
#include "g_shm.h"
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Открытие разделяемого сегмента памяти, */ /* отображение его в адресное пространство процесса, */ /* чтение из сегмента и выдача строк на стандартный вывод */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ int main (void) { int fd_shm; /* Дескриптор объекта в разделяемой */ /* памяти */ void *addr_shm; /* Адрес отображенного в память */ /* объекта */ sigset_t smask; /* Маска ожидаемых сигналов */ siginfo_t sinfo; /* Структура для получения данных*/ /* о сигнале */ /* Длительность ожидания строки */ struct timespec stmspc = {10, 0}; pid_t ppid; /* Идентификатор родительского процесса */
/* Откроем разделяемый сегмент памяти */ if ((fd_shm = shm_open (O_SHM_NAME, O_RDONLY, 0777)) < 0) { perror ("SHM_OPEN"); return (1); }
/* Отобразим сегмент в память */ if ((addr_shm = mmap (NULL, LINE_MAX, PROT_READ, MAP_SHARED, fd_shm, 0)) == MAP_FAILED) { perror ("MMAP-C"); return (2); }
/* Запомним идентификатор родительского процесса */ ppid = getppid ();
/* Сформируем маску ожидаемых сигналов (SIG_SHM) */ (void) sigemptyset (&smask); (void) sigaddset (&smask, SIG_SHM);
/* Подготовительная работа закончена */ fputs ("Вводите строки\n", stdout);
while (sigtimedwait (&smask, &sinfo, &stmspc) == SIG_SHM) { /* Дождались, когда в объекте появилась строка.*/ /* Выдадим ее на стандартный вывод*/ assert (fputs ("Вы ввели: ", stdout) != EOF); assert (fputs (addr_shm, stdout) != EOF); /* Сообщим родительскому процессу, */ /* что данные из объекта извлечены */ assert (kill (ppid, SIG_SHM) == 0); }
return 0; }
Листинг 5.8. Исходный текст порождаемого процесса (файл g_r_shm.c) двухпроцессной программы, копирующей строки со стандартного ввода на стандартный вывод.
Закрыть окно




#include <sys/mman.h> int msync (void *addr, size_t len, int flags);
Листинг 5.9. Описание функции msync().
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа реализует некоторые функции систем управления базами*/ /* данных в памяти, следуя принципу неуничтожения информации */ /* (изменения записываются не в сам объет, а в его новую версию) */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <sys/stat.h> #include s<ys/mman.h> #include <assert.h>
/* Размер страницы */ static int pgsz;
/* Структура для получения */ /* информации об исходном файле*/ static struct stat sbuf_src;
/* Адрес отображенного в память исходного файла*/ static char *saddr;
/* Признак того, что выполнялась функция */ /* обработки сигнала SIGSEGV */ static char sigsegv_catching;
/* * * * * * * * * * * * * * * * * * * * */ /* Функция обработки сигнала SIGSEGV. */ /* Предполагается, что этот сигнал */ /* генерируется при попытке записи в */ /* страницы, доступные только на чтение. */ /* Функция добавляет разрешение на запись*/ /* * * * * * * * * * * * * * * * * * * * */ static void sigsegv_sigaction (int sig, siginfo_t *sig_info, void *addr) { void *page_addr; /* Адрес страницы, в которую*/ /*пытались писать*/
page_addr = (char *) sig_info->si_addr - (off_t) ((char *) sig_info->si_addr - saddr) % pgsz; assert (mprotect (page_addr, pgsz, PROT_READ | PROT_WRITE) == 0); sigsegv_catching = 1; }
/* * * * * * * * * * * * * * * * * * * * * * * */ /* Установка способа обработки сигнала SIGSEGV */ /* * * * * * * * * * * * * * * * * * * * * * * */ static int sigsegv_set_proc (void (*sigsegv_actn) (int, siginfo_t *, void *), struct sigaction *old_sigsegv_sact) { struct sigaction sact;
(void) sigemptyset (&sact.sa_mask); sact.sa_flags = SA_SIGINFO; sact.sa_sigaction = sigsegv_actn; if (sigaction (SIGSEGV, &sact, old_sigsegv_sact) != 0) { perror ("SIGACTION"); return (-1); }
return 0; }
/* * * * * * * * * * * * * * * * * * * * * */ /* Функция начала работы с исходным файлом.*/ /* Нормальный результат равен нулю */ /* * * * * * * * * * * * * * * * * * * * * */ static int init_src (char *name_src) { int fd_src; /* Дескриптор исходного файла */
/* Откроем исходный файл и отобразим его в память */ if ((fd_src = open (name_src, O_RDONLY)) < 0) { perror ("OPEN-SRC"); return (-1); } if (fstat (fd_src, &sbuf_src) != 0) { perror ("FSTAT"); return (-1); } if ((saddr = (char *) mmap (NULL, sbuf_src.st_size, PROT_READ, MAP_PRIVATE, fd_src, 0)) == MAP_FAILED) { perror ("MMAP"); return (-1); }
return 0; } /* * * * * * * * * * * * * * * * * * */ /* Опрос конфигурационных параметров */ /* * * * * * * * * * * * * * * * * * */ static int init_conf_params (void) { if ((pgsz = sysconf (_SC_PAGESIZE)) == -1) { perror ("SYSCONF"); return (-1); }
return 0; }
/* * * * * * * * * * * */ /* Общая инициализация */ /* * * * * * * * * * * */ static int init_all (char *name_src) { if ((init_src (name_src) != 0) || (sigsegv_set_proc (sigsegv_sigaction, (struct sigaction *) NULL) != 0) || (init_conf_params () != 0)) { return (-1); }
return 0; }
/* * * * * * * * * * * * * * * * * */ /* Запись в файл измененных страниц*/ /* * * * * * * * * * * * * * * * * */ static int write_dlt (char *name_dlt) { int fd_dlt; /* Дескриптор файла изменений*/ volatile char tmp; /* Значение пробного байта*/ off_t pos;/* Позиция в отображенной памяти*/
if ((fd_dlt = open (name_dlt, O_CREAT | O_WRONLY | O_TRUNC, 0777)) < 0) { perror ("OPEN-DLT"); return (-1); }
/* Измененные страницы выявим путем пробных записей. */ for (pos = 0; pos < sbuf_src.st_size; pos += pgsz) { tmp = saddr [pos]; sigsegv_catching = 0; saddr [pos] = tmp; if (sigsegv_catching == 0) { /* В страницу удалось записать */ /* без генерации сигнала SIGSEGV.*/ /* Значит, она была доступна на запись.*/ /* Следовательно, ее модифицировали.*/ /* Запишем ее в файл изменений */ (void) lseek (fd_dlt, pos, SEEK_SET); assert (write (fd_dlt, saddr + pos, pgsz) == pgsz); } /* Уберем добавленное разрешение на запись */ assert (mprotect (saddr + pos, pgsz, PROT_READ) == 0); } /* for */
return (close (fd_dlt)); }
/* * * * * * * * * * * * * */ /* Функция main() вызывает */ /* описанные выше функции */ /* и обращается на запись */ /* к отображенной памяти */ /* * * * * * * * * * * * * */ int main (int argc, char *argv []) { if (argc != 3) { fprintf (stderr, "Использование: %s исходный_файл " "файл_изменений\n", argv [0]); return (-1); }
if (init_all (argv [1]) != 0) { fprintf (stderr, "Ошибка инициализации\n"); return (-1); }
printf ("Размер страницы: %d\n" "Адрес отображенного в память исходного файла: %p\n" "Длина отображенного в память исходного файла: %ld\n", pgsz, saddr, sbuf_src.st_size);
saddr [0] = '*';
return (write_dlt (argv [2])); }
Листинг 5.10. Пример программы, использующей файлы, отображенные в память.
Закрыть окно




#include <sys/mman.h> int posix_typed_mem_open (const char *name, int oflag, int tflag);
Листинг 5.11. Описание функции posix_typed_mem_open().
Закрыть окно




#include <sys/mman.h> int posix_typed_mem_get_info ( int fildes, struct posix_typed_mem_info *info);
Листинг 5.12. Описание функции posix_typed_mem_get_info().
Закрыть окно




#include <sys/mman.h> int posix_mem_offset ( const void * restrict addr, size_t len, off_t *restrict off, size_t *restrict contig_len, int *restrict fildes);
Листинг 5.13. Описание функции posix_mem_offset().
Закрыть окно




#include <sys/mman.h> int mlock (const void *addr, size_t len);
Листинг 5.14. Описание функции mlock().
Закрыть окно




#include <sys/mman.h> int munlock (const void *addr, size_t len);
Листинг 5.15. Описание функции munlock().
Закрыть окно




#include <sys/mman.h>
int mlockall (int flags);
int munlockall (void);
Листинг 5.16. Описание функций mlockall() и munlockall().
Закрыть окно




/* * * * * * * * * * * * * * * * * * * * * * */ /* Программа демонстрирует удержание в памяти*/ /* всего адресного пространства процесса, */ /* в том числе стека с учетом возможного роста*/ /* * * * * * * * * * * * * * * * * * * * * * */
#include <stdio.h> #include <sys/mman.h>
#define LOCKED_STACK_SIZE 048576
/* * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Следующая функция нужна, чтобы вызвать рост стека до*/ /* требуемого размера. На всякий случай примем меры для*/ /* защиты от слишком умного оптимизирующего компилятора*/ /* * * * * * * * * * * * * * * * * * * * * * * * * * * */ static int dummy_func (void) { char dummy_arr [LOCKED_STACK_SIZE]; int i; int res = 0;
dummy_arr [0] = 0; for (i = 1; i < LOCKED_STACK_SIZE; i++) { dummy_arr [i] = dummy_arr [i - 1] + i; }
for (i = 0; i < LOCKED_STACK_SIZE; i++) { res += dummy_arr [i]; }
return (res); }
/* * * * * * * * * * * * * * * * * * * * * * * * * */ /* Функция main() вызывает вспомогательную функцию */ /* * * * * * * * * * * * * * * * * * * * * * * * * */ int main (void) { if (mlockall (MCL_CURRENT | MCL_FUTURE) != 0) { perror ("MLOCKALL"); return (1); }
fprintf (stderr, "Результат вспомогательной функции:" "%d\n", dummy_func ());
return 0; }
Листинг 5.17. Пример программы, удерживающей в памяти растущий стек.
Закрыть окно



Содержание раздела