Интерфейс бағдарламалаудағы үзіліс хандалерлары (ISR) – жүйенің жұмысын тоқтатып, дереу қызмет көрсетуге арналған код блогы. Драйверлер мен жүйелік қосылыстар үшін маңызды.
Ағылшыншамен салыстырыңыз: абзацты басыңыз — түпнұсқа терезеде ашылады. Абзац астындағы EN түймесі оны мәтін ішінде көрсетеді.
Мазмұны
Кіріспе
Компьютерлік жүйелер бағдарламалау арнайы блок коды
Computer systems programming special block code
Компьютерлік жүйелер бағдарламалауда үзіліс өңдеуші, сондай-ақ үзіліс қызметтік процедурасы немесе ISR деп те аталады, бұл нақты бір үзіліс жағдайымен байланысты кодтың арнайы блогы. Үзіліс өңдеушілер аппараттық үзілістер, бағдарламалық үзіліс командалары немесе бағдарламалық ерекшеліктер арқылы іске қосылады және құрылғы драйверлерін немесе қорғалған режимдер арасындағы өтулерді, мысалы жүйелік шақыруларды жүзеге асыру үшін қолданылады. Үзіліс өңдеушінің дәстүрлі түрі – аппараттық үзіліс өңдеуші. Аппараттық үзілістер электрлік жағдайлардан немесе цифрлық логикада жүзеге асырылған төменгі деңгейдегі протоколдардан туындайды, әдетте үзіліс векторларының қатаң кодталған кестесі арқылы жіберіледі, нормативтік орындалу ағынына асинхронды түрде (үзіліс маскалау деңгейлеріне рұқсат етілгендей), көбінесе жеке стек қолданылады және үзіліс өңдеушінің орындалу барысында басқа орындалу контексіне (артықшылық деңгейіне) автоматты түрде кіреді. Жалпы, аппараттық үзілістер мен олардың өңдеушілері процессор қазіргі орындап жатқан кодты тоқтатуды қажет ететін жоғары приоритетті жағдайларды өңдеу үшін қолданылады. Кейіннен бағдарламалық жасақтаманың бағдарламалық үзіліс (синхронды үзілістің бір түрі) арқылы дәл сол механизмді іске қосуы ыңғайлы болып табылды. Аппараттық деңгейде қатаң кодталған үзіліс жіберу кестесін пайдаланудың орнына, бағдарламалық үзілістер көбінесе операциялық жүйе деңгейінде кері шақыру функциясының бір түрі ретінде жүзеге асырылады. Үзіліс өңдеушілердің көптеген функциялары бар, олар үзіліске қандай жағдай себеп болды және үзіліс өңдеушінің өзінің міндетін орындау жылдамдығына байланысты өзгереді. Мысалы, компьютерлік пернетақтадағы түймелерді басу немесе тышқанды жылжыту, түймелерді немесе тышқанның орнын оқитын және тиісті ақпаратты компьютер жадына көшіретін үзілістерді шақырады. Үзіліс өңдеуші – оқиға өңдеушілердің төменгі деңгейдегі әріптесі. Дегенмен, үзіліс өңдеушілердің ерекше орындалу контексі бар, уақыт және кеңістік бойынша көптеген қатаң шектеулер бар, ал олардың ішкі асинхронды табиғаты стандартты тәжірибемен оларды жөндеуді өте қиын етеді (қайта жаңғыртылатын тест жағдайлары көбінесе болмайды), осылайша арнайы біліктерді талап етеді – жүйелік бағдарламалаудың маңызды кіші жиынтығы – аппараттық үзіліс қабатындағы бағдарламалық жасақтама инженерлері.
In computer systems programming, an interrupt handler, also known as an interrupt service routine or ISR, is a special block of code associated with a specific interrupt condition. Interrupt handlers are initiated by hardware interrupts, software interrupt instructions, or software exceptions, and are used for implementing device drivers or transitions between protected modes of operation, such as system calls. The traditional form of interrupt handler is the hardware interrupt handler. Hardware interrupts arise from electrical conditions or low level protocols implemented in digital logic, are usually dispatched via a hard coded table of interrupt vectors, asynchronously to the normal execution stream (as interrupt masking levels permit), often using a separate stack, and automatically entering into a different execution context (privilege level) for the duration of the interrupt handler's execution. In general, hardware interrupts and their handlers are used to handle high priority conditions that require the interruption of the current code the processor is executing. Later it was found convenient for software to be able to trigger the same mechanism by means of a software interrupt (a form of synchronous interrupt). Rather than using a hard coded interrupt dispatch table at the hardware level, software interrupts are often implemented at the operating system level as a form of callback function. Interrupt handlers have a multitude of functions, which vary based on what triggered the interrupt and the speed at which the interrupt handler completes its task. For example, pressing a key on a computer keyboard, or moving the mouse, triggers interrupts that call interrupt handlers which read the key, or the mouse's position, and copy the associated information into the computer's memory. An interrupt handler is a low level counterpart of event handlers. However, interrupt handlers have an unusual execution context, many harsh constraints in time and space, and their intrinsically asynchronous nature makes them notoriously difficult to debug by standard practice (reproducible test cases generally don't exist), thus demanding a specialized skillset—an important subset of system programming—of software engineers who engage at the hardware interrupt layer.
Тоқтату белгілері
Басқа оқиғаларды өңдеушілерден өзгеше, үзіліс өңдеушілер өздерінің негізгі функционалының бір бөлігі ретінде үзіліс белгілерін тиісті мәндерге орнатуы керек. Тіпті ішкі үзілістерді қолдайтын процессорда да, өңдеушіге процессордың аппараттық операциясы арқылы барлық үзілістер жасырылған күйде жетеді. Мұндай архитектурада үзіліс өңдеуші әдетте қажетті ең аз контексті сақтайды, содан кейін мүмкіндігі бірінші болып туғанда жаһандық үзіліс тежеуін алып тастайды, осылайша жоғары басымдылықтағы үзілістер ағымдағы өңдеушіні үзуге мүмкіндік алады. Сондай-ақ, үзіліс өңдеушінің ағымдағы үзіліс көзін қандай да бір тәсілмен (көбінесе перифериялық тіркелгіштегі белгілі бір битті ауыстыру арқылы) басуы маңызды, осылайша ағымдағы үзіліс өңдеушіден шыққанда бірден қайталанбауына және шексіз циклге түспеуіне болады. Кез келген жағдайда үзіліс жүйесін дәл дұрыс күйде қалдырып үзіліс өңдеушіні аяқтау кейде қиын және аса талапты міндет болуы мүмкін, ал оның қате басқарылуы жүйені толығымен тоқтататын көптеген ауыр қателерге себеп болады. Бұл қателер кейде үзіліссіз болады, дұрыс емес жағдайлар апталар немесе айлар бойы үздіксіз жұмыс істемейді. Үзіліс өңдеушілерді формалды түрде тексеру өте қиын, ал сынақ әдетте тек ең көп кездесетін қателерді анықтайды, сондықтан үзіліс өңдеушілердегі шағын, үзіліссіз қателер жиі соңғы тұтынушыларға жеткізіледі.
Unlike other event handlers, interrupt handlers are expected to set interrupt flags to appropriate values as part of their core functionality. Even in a CPU which supports nested interrupts, a handler is often reached with all interrupts globally masked by a CPU hardware operation. In this architecture, an interrupt handler would normally save the smallest amount of context necessary, and then reset the global interrupt disable flag at the first opportunity, to permit higher priority interrupts to interrupt the current handler. It is also important for the interrupt handler to quell the current interrupt source by some method (often toggling a flag bit of some kind in a peripheral register) so that the current interrupt isn't immediately repeated on handler exit, resulting in an infinite loop. Exiting an interrupt handler with the interrupt system in exactly the right state under every eventuality can sometimes be an arduous and exacting task, and its mishandling is the source of many serious bugs, of the kind that halt the system completely. These bugs are sometimes intermittent, with the mishandled edge case not occurring for weeks or months of continuous operation. Formal validation of interrupt handlers is tremendously difficult, while testing typically identifies only the most frequent failure modes, thus subtle, intermittent bugs in interrupt handlers often ship to end customers.
Орындау контексі
Қазіргі операциялық жүйеде аппараттық үзіліс басқарушысының орындалу контексіне кіргенде, бұл өте күрделі. Орындалу жылдамдығын арттыру мақсатында, басқарушы әдетте жұмыс істеп жатқан процестің жады және орындалу контекстінде басталады, оған ешқандай арнайы байланысы жоқ (үзіліс, негізінен, жұмыс істеп жатқан контексті басып алады – процестің уақытын есепке алу жүйесі үзілісті өңдеуге кеткен уақытты үзілген процеске қосады). Дегенмен, үзілген процестен өзгеше, үзіліс әдетте аппараттық ресурстарға тікелей қол жеткізуге жеткілікті жоғары құқық деңгейіне, аппараттық құралдармен қамтамасыз етілген механизм арқылы көтеріледі.
In a modern operating system, upon entry the execution context of a hardware interrupt handler is subtle. For reasons of performance, the handler will typically be initiated in the memory and execution context of the running process, to which it has no special connection (the interrupt is essentially usurping the running context—process time accounting will often accrue time spent handling interrupts to the interrupted process). However, unlike the interrupted process, the interrupt is usually elevated by a hard coded CPU mechanism to a privilege level high enough to access hardware resources directly.
Қорытындылау
Төмен деңгейдегі микробасқарушыда чипте қорғаныс режимдері болмауы мүмкін және жад басқару бірлігі (MMU) болмауы да мүмкін. Мұндай чиптерде үзіліс иесінің орындалу контексі үзіліске ұшыраған бағдарламамен шамалас болады, ол әдетте кішкентай, белгілі бір мөлшердегі стекте жұмыс істейді (жад ресурстары дәстүрлі түрде төменгі деңгейде өте шектеулі болған). Көбінесе тігілген үзілістер қолданылады, бұл стек пайдалануды күшейтеді. Бұл бағдарламалау жұмысында үзіліс иесінің басты шектеуі – ең жаман жағдайда қол жетімді стекке аспау, бұл бағдарламалаушыдан әрбір іске асырылған үзіліс иесі мен қолданба тапсырмасының стекке қажетті кеңістігі туралы толыққанды ойлануды талап етеді. Бөлінген стек кеңістігінің шегінен асып кеткен жағдайда (стек ағыны деп аталатын жағдай), мұндай чиптерде аппараттық деңгейде анықтау мүмкін емес. Егер стек басқа жазуға болатын жад аймағына асып өтіп кетсе, иесі әдетте күтілгендей жұмыс істейді, бірақ қолданба кейінірек (кейде өте кейінірек) иенің жанама әсерінен туындаған жадтың бұзылуына байланысты сәтсіздікке ұшырайды. Егер стек жазуға рұқсат етілмейтін (немесе қорғалған) жад аймағына асып өтіп кетсе, қате әдетте иенің өзінде пайда болады (әдетте кейін түзету оңай). Жазуға болатын жағдайда, жүйе дұрыс жұмыс істесе, оның мәні жазылмайтын, заңды стек соңынан кейінгі тұрақты мәнді сақтайтын стек күзетшісін іске асыруға болады. Күзетшінің сыбайлас жемқорлыққа ұшырауын үнемі бақылау үшін бақылаушы механизмдерді пайдалану жиі кездеседі. Бұл көптеген стек ағыны жағдайларын осы мәселені тудырған операцияға жақын уақытта анықтайды. Көп тапсырмалы жүйеде әр орындалу тізбегінің өз стегі болады. Егер үзілістер үшін арнайы жүйелік стек қарастырылмаса, үзілістер үзіліске ұшыраған тізбектің стек кеңістігін пайдаланады. Мұндай жобаларда әдетте MMU болады, ал пайдаланушы стектері стектің ағыны MMU арқылы ұсталып қалады, яғни жүйелік қате ретінде (түзету үшін) немесе жадты кеңейту үшін жадты қайта карталау арқылы. Микробасқарушының осы деңгейіндегі жад ресурстары әдетте айтарлықтай шектеулі емес, сондықтан стектерге кең қауіпсіздік жиегімен жад бөлуге болады. Көп тізбекті жүйелерде аппараттық үзіліс механизмі стекті арнайы жүйелік стекке ауыстырған абзал, сонда ешбір тізбек стегі ең жаман жағдайда тігілген үзілістерді пайдалануды ескеруге қажеттілік туындамайды. 1978 жылғы 8 биттік Motorola 6809 сияқты кішкентай процессорлар жеке жүйелік және пайдаланушы стектеріне сілтемелерді ұсынды.
In a low level microcontroller, the chip might lack protection modes and have no memory management unit (MMU). In these chips, the execution context of an interrupt handler will be essentially the same as the interrupted program, which typically runs on a small stack of fixed size (memory resources have traditionally been extremely scant at the low end). Nested interrupts are often provided, which exacerbates stack usage. A primary constraint on the interrupt handler in this programming endeavour is to not exceed the available stack in the worst case condition, requiring the programmer to reason globally about the stack space requirement of every implemented interrupt handler and application task. When allocated stack space is exceeded (a condition known as a stack overflow), this is not normally detected in hardware by chips of this class. If the stack is exceeded into another writable memory area, the handler will typically work as expected, but the application will fail later (sometimes much later) due to the handler's side effect of memory corruption. If the stack is exceeded into a non writable (or protected) memory area, the failure will usually occur inside the handler itself (generally the easier case to later debug). In the writable case, one can implement a sentinel stack guard—a fixed value right beyond the end of the legal stack whose value can be overwritten, but never will be if the system operates correctly. It is common to regularly observe corruption of the stack guard with some kind of watch dog mechanism. This will catch the majority of stack overflow conditions at a point in time close to the offending operation. In a multitasking system, each thread of execution will typically have its own stack. If no special system stack is provided for interrupts, interrupts will consume stack space from whatever thread of execution is interrupted. These designs usually contain an MMU, and the user stacks are usually configured such that stack overflow is trapped by the MMU, either as a system error (for debugging) or to remap memory to extend the space available. Memory resources at this level of microcontroller are typically far less constrained, so that stacks can be allocated with a generous safety margin. In systems supporting high thread counts, it is better if the hardware interrupt mechanism switches the stack to a special system stack, so that none of the thread stacks need account for worst case nested interrupt usage. Tiny CPUs as far back as the 8 bit Motorola 6809 from 1978 have provided separate system and user stack pointers.
Уақыт пен бір мезгілделік шектеулері
Көптеген себептерге байланысты, үзіліс жолдамасының мүмкіндігінше жылдам орындалуы өте қажет, ал аппараттық үзілістің тоқтатуға болатын жүйелік шақыруларды шақыруына жол берілмейді (немесе қатаң тыйым салынған). Бірнеше өңдеу ядросы бар жүйеде қайта кіру мүмкіндігін ескеру де аса маңызды. Егер жүйе аппараттық DMA-ны қолдаса, бір ғана CPU ядросы болған жағдайда да бір уақытта орындалу мәселелері туындауы мүмкін. (Орта деңгейдегі микроконтроллерде қорғау деңгейлері мен MMU болмауы, бірақ көптеген арналары бар DMA қозғалтқышының болуы сирек емес; мұндай жағдайда көптеген үзілістер DMA қозғалтқышымен туындайды, ал тиісті үзіліс жолдамасының абайсызда әрекет етуі күтіледі.) Қазіргі заманғы тәжірибе аппараттық үзіліс жолдамаларын алдыңғы және артқы бөліктерге бөлуге қарайды. Алдыңғы бөлік (немесе бірінші деңгей) жұмыс істеп жатқан процесс аясында бастапқы үзілісті қабылдайды, аппараттық құралды жедел емес жағдайға келтіру үшін ең аз жұмыс атқарады (мысалы, толық қабылдау буферін босату) және содан кейін артқы бөлікті (немесе екінші деңгейді) жақын арада, тиісті кезектілік бойынша орындалу үшін белгілейді; іске қосылғаннан кейін артқы бөлік өз процесінің контекстінде, азырақ шектеулермен жұмыс істейді және жолдаманың логикалық операциясын аяқтайды (мысалы, жаңа алынған деректерді операциялық жүйенің дерек кезегіне жіберу).
For many reasons, it is highly desired that the interrupt handler execute as briefly as possible, and it is highly discouraged (or forbidden) for a hardware interrupt to invoke potentially blocking system calls. In a system with multiple execution cores, considerations of reentrancy are also paramount. If the system provides for hardware DMA, concurrency issues can arise even with only a single CPU core. (It is not uncommon for a mid tier microcontroller to lack protection levels and an MMU, but still provide a DMA engine with many channels; in this scenario, many interrupts are typically triggered by the DMA engine itself, and the associated interrupt handler is expected to tread carefully.) A modern practice has evolved to divide hardware interrupt handlers into front half and back half elements. The front half (or first level) receives the initial interrupt in the context of the running process, does the minimal work to restore the hardware to a less urgent condition (such as emptying a full receive buffer) and then marks the back half (or second level) for execution in the near future at the appropriate scheduling priority; once invoked, the back half operates in its own process context with fewer restrictions and completes the handler's logical operation (such as conveying the newly received data to an operating system data queue).
Қазіргі операциялық жүйелердегі бөлінген өңдеушілер
Бірнеше операциялық жүйелерде – Linux, Unix, macOS, Microsoft Windows, z/OS, DESQview және басқа да бұрын қолданылған операциялық жүйелерде – үзіліс басқарушылары екі бөлікке бөлінеді: Бірінші деңгейлі үзіліс басқарушы (FLIH) және Екінші деңгейлі үзіліс басқарушылар (SLIH). FLIH-тар «қатты үзіліс басқарушысы» немесе «жылдам үзіліс басқарушысы» деп те аталады, ал SLIH-тар «баяу/жұмсақ үзіліс басқарушысы» немесе Windows жүйесіндегі «Кейінге қалдырылған процедура шақыруы» деп те аталады. FLIH платформаға тән үзіліс процедураларын жүзеге асырады, бұл үзіліс ретімен тікелей орындалады. Үзіліске жауап ретінде контексттік ауыстыру жүзеге асырылады, үзіліс коды жүктеліп, орындалады. FLIH-тің міндеті – үзіліске жылдам қызмет көрсету немесе үзіліс кезінде ғана қолжетімді болатын платформаға тән маңызды ақпаратты сақтау, сондай-ақ SLIH-тің одан әрі ұзақ үзіліс өңдеуін жоспарлау. FLIH процестерді орындауда кешігуге себеп болады. FLIH-тар сонымен қатар үзілістерді маскилейді. Кешігуді азайту нақты уақыт операциялық жүйелері үшін маңызды, себебі олар белгілі бір кодтың орындалуы келісілген уақыт ішінде аяқталуын қамтамасыз етуі керек. Кешігуді азайту және маскиленген үзілістерден деректерді жоғалту мүмкіндігін азайту үшін бағдарламашылар FLIH-тің орындалу уақытын барынша азайтуға тырысады, мүмкіндігінше көп функцияларды SLIH-ке көшіреді. Қазіргі заманғы компьютерлердің жылдамдығын ескере отырып, FLIH барлық құрылғыға және платформаға тәуелді өңдеуді жүзеге асыруы мүмкін, ал SLIH платформадан тәуелсіз ұзақ үзіліс өңдеуі үшін қолданылады. Аппараттық құралдарға қызмет көрсететін FLIH әдетте өзінің орындалуы аяқталғанға дейін байланысты үзілісін маскилейді (немесе жасырып ұстайды). Өзінің байланысты үзілісін аяқтамай тұрып ашатын (сирек кездесетін) FLIH «қайта кіретін үзіліс басқарушысы» деп аталады. Қайта кіретін үзіліс басқарушылары бір үзіліс векторының бірнеше рет шақырылуынан стек асуына әкелуі мүмкін, сондықтан олардан әдетте аулақ тұрады. Басымдықпен үзіліс жүйесінде FLIH басқа да бірдей немесе төмен басымдықты үзілістерді (құысқа уақытқа) маскилейді. SLIH ұзақ үзіліс өңдеу тапсырмаларын процеске ұқсас түрде орындайды. SLIH әрбір басқарушыға арналған арнайы ядролық жіп немесе ядролық жұмысшы жіптерінің пулы арқылы орындалады. Бұл жіптер операциялық жүйедегі орындалу кезегінде процессор уақыты үзіліс өңдеуі үшін қолжетімді болғанға дейін күтеді. SLIH ұзақ уақыт орындалуы мүмкін, сондықтан олар әдетте жіптер мен процестерге ұқсас жоспарланады. Linux жүйесінде FLIH «жоғарғы жартысы», ал SLIH «төменгі жартысы» немесе «төменгі бөлігі» деп аталады. Бұл басқа Unix сияқты жүйелерде қолданылатын атаудан өзгеше, онда екеуі де төменгі бөліктің құрамы болып табылады.
In several operating systemsLinux, Unix, macOS, Microsoft Windows, z/OS, DESQview and some other operating systems used in the pastinterrupt handlers are divided into two parts: the First Level Interrupt Handler (FLIH) and the Second Level Interrupt Handlers (SLIH). FLIHs are also known as hard interrupt handlers or fast interrupt handlers, and SLIHs are also known as slow/soft interrupt handlers, or Deferred Procedure Calls in Windows. A FLIH implements at minimum platform specific interrupt handling similar to interrupt routines. In response to an interrupt, there is a context switch, and the code for the interrupt is loaded and executed. The job of a FLIH is to quickly service the interrupt, or to record platform specific critical information which is only available at the time of the interrupt, and schedule the execution of a SLIH for further long lived interrupt handling. FLIHs cause jitter in process execution. FLIHs also mask interrupts. Reducing the jitter is most important for real time operating systems, since they must maintain a guarantee that execution of specific code will complete within an agreed amount of time. To reduce jitter and to reduce the potential for losing data from masked interrupts, programmers attempt to minimize the execution time of a FLIH, moving as much as possible to the SLIH. With the speed of modern computers, FLIHs may implement all device and platform dependent handling, and use a SLIH for further platform independent long lived handling. FLIHs which service hardware typically mask their associated interrupt (or keep it masked as the case may be) until they complete their execution. An (unusual) FLIH which unmasks its associated interrupt before it completes is called a reentrant interrupt handler. Reentrant interrupt handlers might cause a stack overflow from multiple preemptions by the same interrupt vector, and so they are usually avoided. In a priority interrupt system, the FLIH also (briefly) masks other interrupts of equal or lesser priority. A SLIH completes long interrupt processing tasks similarly to a process. SLIHs either have a dedicated kernel thread for each handler, or are executed by a pool of kernel worker threads. These threads sit on a run queue in the operating system until processor time is available for them to perform processing for the interrupt. SLIHs may have a long lived execution time, and thus are typically scheduled similarly to threads and processes. In Linux, FLIHs are called upper half, and SLIHs are called lower half or bottom half. This is different from naming used in other Unix like systems, where both are a part of bottom half.