프로그램 카운터는 전원이 공급되는 동안 연속된 값들을 가정한다. 인스트럭션에 의해 이러한 연속된 값들의 다음으로 넘어가는 전환은 제어이동이라고 부르며 이러한 제어이동의 배열은 제어흐름이라고 부른다.
이렇게 점진적으로 진행되는 제어흐름만 있다면 별 일 없겠지만 프로그램 변수에 의한 내부 프로그램 상태 변화에 프로그램이 반응하려면 인접해있지 않은 값으로 전환되는 제어흐름이 일어나기도 한다.
또한 시스템들은 내부 프로그램 변수에 의해 표시되지 않으며 프로그램 실행과는 관련없는 시스템 상태의 변화에도 반응할 수 있어야 한다.(하드웨어 타이머가 꺼지거나, 패킷이 네트워크 어댑터를 통해 도착하거나, 디스크로부터 데이터를 요청한 프로그램이 응답을 받을 때 까지 잠든다거나, 부모 프로세스에 의해 생성된 자식 프로세스가 종료될 때 부모 프로세스에게 통지가 간다거나)
현대의 시스템들은 제어흐름의 갑작스러운 변화를 만드는 방법으로 이러한 상황에 반응한다. 이를 예외적인 제어 흐름(ECF)라고 부른다. 이러한 ECF는 컴퓨터 시스템의 모든 수준에서 발생한다.
하드웨어 수준에서 하드웨어에 의해 검출되는 예외 핸들러로 갑작스런 제어이동을 발생시킨다.
운영체제 커널수준의 문맥 전환을 통해서 사용자 프로세스에서 다른 프로세스로 제어가 이동한다.
응용 수준에서 프로세스는 시그널 핸들러로 제어를 급격히 이동하는 다른 프로세스로 시그널을 보낼 수 있다.
개별 프로그램은 일반적인 스택 운영을 회피하고 다른 함수 내의 임의의 위치로 비지역성 점프를 하는 방법으로 에러에 대응한다.
예외상황은 하드웨어와 운영체제에 의해 구현된 예외적인 제어흐름의 한가지 형태이다.
프로세서가 이벤트가 발생했다는 것을 감지하면, 예외 테이블이라고 하는 점프 테이블을 통해서 이 특정 종류의 이벤트를 처리하기 위해 특별히 설계된 운영체제 서브루틴(예외처리 핸들러)으로 간접 프로시저 콜을 하게 된다.
예외처리 핸들러가 처리를 끝마치면 예외상황을 발생시킨 이벤트의 조율에 따라 다음 3가지 중 하나가 일어난다.
한 시스템 내에선 가능한 예외상황의 종류마다 중복되지 않는 양의 정수를 예외번호로 할당하고 있다. 이 숫자는 일부는 프로세서 설계자가, 나머지는 운영체제 커널 설계자가 할당한다.
전자는 0으로 나누기, 페이지 오류, 메모리 접근 위반, breakpoint, 산술연산 오버플로우가 포함된다. 후자에는 시스템콜, 외부 I/O디바이스로부터의 시그널이 포함된다.
시스템이 프로그램을 실행하고 이씅 ㄹ때 프로세서는 이벤트가 발생했다는 것을 감지하고 대응되는 예외번호 K를 결정한다. 프로세서는 그 후에 예외테이블의 엔트리 k를 통해 간접 프로시저 콜을 하는 방법으로 예외상황을 발생시킨다.
프로세서 외부에 있는 입출력 디바이스로부터의 시그널의 결과로 비동기적(async)으로 발생한다.
디스크 컨트롤러, 타이머칩 같은 입출력 디바이스들은 프로세서 칩의 핀에 시그널을 보낸다.
현재의 인스트럭션 실행을 완료한 후에, 프로세서는 인터럽트 핀이 high로 올라갔다는 것을 발견하고 적절한 인터럽트 핸들러를 호출한다. 핸들러가 리턴할 때, 제어를 다음 인스트럭션으로 돌려주며 이는 인터럽트가 마치 발생하지 않았던 것 처럼 보여주는 효과를 낸다.
트랩은 의도적인 예외상황으로 어떤 인스트럭션을 실행한 결과로 발생한다. 이 후 트랩 핸들러는 제어를 다음 인스트럭션으로 리턴한다. 트랩의 가장 중요한 사용은 시스템 콜이라고 알려진 사용자 프로그램과 커널 사이의 프로시저와 유사한 인터페이스를 제공하는 것이다.
사용자 프로그램은 파일을 읽고read, 만들고fork, 로드하고execve, 종료하는 등의 서비스를 커널에게 요청할 필요가 있다. 시스템 콜은 커널 모드에서 돌아가며 이로 인해 커널 내에서 정의된 스택에 접근하며, 특권을 가진 인스트럭션을 실행할 수 있도록 해준다.
오류는 핸들러가 정정할 수 있을 가능성이 있는 에러조건으로부터 발생한다. 오류가 발생하면 프로세서는 제어를 오류 핸들러로 이동해준다. 만일 핸들러가 에러 조건을 정정할 수 있다면, 제어를 오류를 발생시킨 인스트럭션으로 돌려주어서 거기서부터 재실행한다. 그럴수 없다면, 핸들러는 커널 내부의 abort 루틴으로 리턴해서 응용프로그램을 종료한다.
중단은 DRAM이나 SRAM이 고장날 때 발생하는 패리티 에러와 하드웨어 같은 복구할 수 없는 치명적인 에러에서 발생한다. 응용프로그램으로 제어를 다시 리턴하지 않는다.
리눅스는 파일을 읽고 쓰고 새 프로세스를 만들 때 응용프로그램이 사용할 수 있는 수백개의 시스템 콜을 제공한다. x86-64시스템에서 시스템 콜은 syscall이라고 부르는 트랩 인스트럭션을 통해서 제공된다.
프로세스와 커널이 다른 프로세스를 중단하도록 하는 예외적 제어흐름이다.
시그널은 다음 두 가지 이유 중 하나로 배달된다.
1. 커널이 0으로 나누기나 자식 프로세스의 종료 같은 시스템 이벤트를 감지했다.
2. 어떤 프로세스가 커널에 명시적으로 시그널을 목적지 프로세스에 보낼 것을 요구하기 위해 kill함수를 호출하였다.
목적지 프로세스는 배달된 신호에 대해서 커널이 어떤 방식으로 반응해야 할 때 목적지 프로세스는 시그널을 받는다. 프로세스는 시그널 핸들러라고 부르는 사용자수준 함수를 실행해서 시그널을 무시하거나, 종료하거나, 잡을 수 있다.
보내졌지만 아직 받지 않은 시그널은 펜딩 시그런이라고 부른다. 만일 어떤 프로세스가 타입K의 펜딩 시그널을 갖고 있다면 이 프로세스로 다음에 발생하는 타입K의 시그널은 큐에 들어가지 않으며 그냥 버려진다.