Новые книги

Сегодня рекламе не доверяют 60 % населения, при этом эмоциональным советам друзей доверяют почти все. В эпоху, когда свадебный ролик на YouTube за несколько минут могут посмотреть 50 000 человек, а остроумную фразу в Twitter перепостить миллионы, пора по-новому отнестись к социальным сетям, интерактивным онлайн-сервисам и популярным сайтам.

Авторы «Эффекта стрекозы» выбрали самые громкие интернет-кейсы, изучив нашумевшие промо-кампании (здесь есть истории о Бараке Обаме, спасенных жизнях, волшебных купонах и чудесных стартапах, которые мгновенно стали легендарными), и на их основе разработали специальный подход к созданию маркетинговой стратегии в виртуальном мире. Если вы хотите продвинуть продукт, услугу или некоммерческий проект через Интернет и сделать это высококлассно, то… приглашаем в полет!
Курс знакомит с языком программирования Perl, с его принципами, основными возможностями и особенностями в объёме, достаточном, чтобы начать разрабатывать прикладные и системные задачи, включая программирование для сети Интернет.

Курс является достаточно подробным введением в язык программирования Perl. Описывается уникальная культура Perl и особенности, отличающие его от других языков программирования и во многом обусловившие его популярность. Рассматриваются основные средства программирования на языке Perl версии 5.8. Разбираются богатые возможности языка для создания самых разных приложений, а также особый стиль программирования на Perl. Курс ориентирован на студентов, начинающих программистов или разработчиков, применяющих другие языки и желающих писать прикладные или системные программы на Perl.

7.7 ИЗМЕНЕНИЕ РАЗМЕРА ПРОЦЕССА

 

7.7 ИЗМЕНЕНИЕ РАЗМЕРА ПРОЦЕССА

С помощью системной функции brk процесс может увеличивать и уменьшать размер области данных. Синтаксис вызова функции:

   brk(endds);

где endds - старший виртуальный адрес области данных процесса (адрес верхней границы). С другой стороны, пользователь может обратиться к функции следующим образом:

   oldendds = sbrk(increment);

где oldendds - текущий адрес верхней границы области, increment - число байт, на которое изменяется значение oldendds в результате выполнения функции. Sbrk - это имя стандартной библиотечной подпрограммы на Си, вызывающей функцию brk. Если размер области данных процесса в результате выполнения функции увеличивается, вновь выделяемое пространство имеет виртуальные адреса, смежные с адресами увеличиваемой области; таким образом, виртуальное адресное пространство процесса расширяется. При этом ядро проверяет, не превышает ли новый размер процесса максимально-допустимое значение, принятое для него в системе, а также не накладывается ли новая область данных процесса на виртуальное адресное пространство, отведенное ранее для других целей (Рисунок 7.26). Если все в порядке, ядро запускает алгоритм growreg, присоединяя к области данных внешнюю память (например, таблицы страниц) и увеличивая значение поля, описывающего размер процесса. В системе с замещением страниц ядро также отводит под новую область пространство основной памяти и обнуляет его содержимое; если свободной памяти нет, ядро освобождает память путем выгрузки процесса (более подробно об этом мы поговорим в главе 9). Если с помощью функции brk процесс уменьшает размер области данных, ядро освобождает часть ранее выделенного адресного пространства; когда процесс попытается обратиться к данным по виртуальным адресам, принадлежащим освобожденному пространству, он столкнется с ошибкой адресации.

  
     алгоритм brk                                               
     входная информация:  новый адрес верхней границы области   
                          данных                                
     выходная информация: старый адрес верхней границы области  
                          данных                                
     {                                                          
         заблокировать область данных процесса;                 
         если (размер области увеличивается)                    
              если (новый размер области имеет недопустимое зна-
               чение)                                           
              {                                                 
                   снять блокировку с области;                  
                   вернуть (ошибку);                            
              }                                                 
         изменить размер области (алгоритм growreg);            
         обнулить содержимое присоединяемого пространства;      
         снять блокировку с области данных;                     
     }                                                          

Рисунок 7.26. Алгоритм выполнения функции brk

На Рисунке 7.27 приведен пример программы, использующей функцию brk, и выходные данные, полученные в результате ее прогона на машине AT&T 3B20. Вызвав функцию signal и распорядившись принимать сигналы о нарушении сегментации (segmentation violation), процесс обращается к подпрограмме sbrk и выводит на печать первоначальное значение адреса верхней границы области данных. Затем в цикле, используя счетчик символов, процесс заполняет область данных до тех пор, пока не обратится к адресу, расположенному за пределами области, тем самым давая повод для сигнала о нарушении сегментации. Получив сигнал, функция обработки сигнала вызывает подпрограмму sbrk для того, чтобы присоединить к области дополнительно 256 байт памяти; процесс продолжается с точки прерывания, заполняя информацией вновь выделенное пространство памяти и т.д. На машинах со страничной организацией памяти, таких как 3B20, наблюдается интересный феномен. Страница является наименьшей единицей памяти, с которой работают механизмы аппаратной защиты, поэтому аппаратные средства не в состоянии установить ошибку в граничной ситуации, когда процесс пытается записать информацию по адресам, превышающим верхнюю границу области данных, но принадлежащим т.н. "полулегальной" странице (странице, не полностью занятой областью данных процесса). Это видно из результатов выполнения программы, выведенных на печать (Рисунок 7.27): первый раз подпрограмма sbrk возвращает значение 140924, то есть адрес, не дотягивающий 388 байт до конца страницы, которая на машине 3B20 имеет размер 2 Кбайта. Однако процесс получит ошибку только в том случае, если обратится к следующей странице памяти, то есть к любому адресу, начиная с 141312. Функция обработки сигнала прибавляет к адресу верхней границы области 256, делая его равным 141180 и, таким образом, оставляя его в пределах текущей страницы. Следовательно, процесс тут же снова получит ошибку, выдав на печать адрес 141312. Исполнив подпрограмму sbrk еще раз, ядро выделяет под данные процесса новую страницу памяти, так что процесс получает возможность адресовать дополнительно 2 Кбайта памяти, до адреса 143360, даже если верхняя граница области располагается ниже. Получив ошибку, процесс должен будет восемь раз обратиться к подпрограмме sbrk, прежде чем сможет продолжить выполнение основной программы. Таким образом, процесс может иногда выходить за официальную верхнюю границу области данных, хотя это и нежелательный момент в практике программирования.

Когда стек задачи переполняется, ядро автоматически увеличивает его размер, выполняя алгоритм, похожий на алгоритм функции brk. Первоначально стек задачи имеет размер, достаточный для хранения параметров функции exec, однако при выполнении процесса этот стек может переполниться. Переполнение стека приводит к ошибке адресации, свидетельствующей о попытке процесса обратиться к ячейке памяти за пределами отведенного адресного пространства. Ядро устанавливает причину возникновения ошибки, сравнивая текущее значение указателя вершины стека с размером области стека. При расширении области стека ядро использует точно такой же механизм, что и для области данных. На выходе из прерывания процесс имеет область стека необходимого для продолжения работы размера.

   
     #include <signal.h>                                   
     char *cp;                                             
     int callno;                                           
                                                           
     main()                                                
     {                                                     
           char *sbrk();                                   
           extern catcher();                               
                                                           
           signal(SIGSEGV,catcher);                        
           cp = sbrk(0);                                   
           printf("original brk value %u\n",cp);           
           for (;;)                                        
                   *cp++ = 1;                              
     }                                                     
                                                           
     catcher(signo);                                       
           int signo;                                      
     {                                                     
           callno++;                                       
           printf("caught sig %d %dth call at addr %u\n",  
                  signo,callno,cp);                        
           sbrk(256);                                      
           signal(SIGSEGV,catcher);                        
     }                                                     

           original brk value 140924                 
           caught sig 11 1th call at addr 141312     
           caught sig 11 2th call at addr 141312     
           caught sig 11 3th call at addr 143360     
             ...(тот же адрес печатается до 10-го    
                 вызова подпрограммы sbrk)           
           caught sig 11 10th call at addr 143360    
           caught sig 11 11th call at addr 145408    
             ...(тот же адрес печатается до 18-го    
                 вызова подпрограммы sbrk)           
           caught sig 11 18th call at addr 145408    
           caught sig 11 19th call at addr 145408    
                         -                           
                         -                           

Рисунок 7.27. Пример программы, использующей функцию brk, и результаты ее контрольного прогона


     /* чтение командной строки до символа конца файла */       
     while (read(stdin,buffer,numchars))                        
     {                                                          
         /* синтаксический разбор командной строки */           
         if (/* командная строка содержит & */)                 
                amper = 1;                                      
         else                                                   
                amper = 0;                                      
         /* для команд, не являющихся конструкциями командного  
            языка shell */                                      
         if (fork() == 0)                                       
         {                                                      
                /* переадресация ввода-вывода? */              
                if (/* переадресация вывода */)                 
                {                                               
                      fd = creat(newfile,fmask);                
                      close(stdout);                            
                      dup(fd);                                  
                      close(fd);                                
                      /* stdout теперь переадресован */         
                }                                               
                if (/* используются каналы */)                  
                {                                               
                      pipe(fildes);                             
                                                                

Рисунок 7.28. Основной цикл программы shell

Предыдущая глава || Оглавление || Следующая глава