2023. 11. 4. 04:39ㆍ그림 리눅스
프로그램과 프로세스
프로그램이란 컴퓨터에서 동작하는 관련된 명령 및 데이터를 하나로 묶은 것입니다. 커널도 프로그램의 일종입니다.
리눅스에서 동작하는 프로그램의 종류(예):
- 웹브라우저: 크롬, 파이어폭스 등
- 오피스 프로그램: 리브레오피스 등
- 웹서버: 아파치, 엔진엑스 등
- 텍스트 에디터: 빔, 이멕스 등
- 프로그래밍 언어 관련: C 컴파일러, GO 컴파일러, 파이썬 인터프리터 등
- 셸: bash, zsh 등
- 시스템 전체 관리 소프트웨어: systemd 등
실행도어서 동작 중인 프로그램을 "프로세스"라고 부릅니다.
커널
커널의 무엇이고, 왜 필요할까...
프로세스가 직접 저장 장치에 접근 가능한 시스템을 가정해 보자.
이떄 동시에 데이터를 읽고 쓰려면 엉망이 될 것이다.
- 명령 A : 데이터를 읽고 쓸 장소를 지정합니다.
- 명령 B : 명령 A에서 지정한 장소에 데이터를 읽고 씁니다.
이런 시스템에서 프로세스 0이 데이터를 쓰는 작업과 프로세스 1이 다른 장소에서 데이터를 읽는작업이 동시에 발생하면 다음과 같은 순서로 명령이 호출될 가능성이 있습니다.
- 프로세스 0이 데이터를 쓸 장소를 지정(프로세스 0이 명령 A를 호출)
- 프로세스 1이 데이터를 읽을 장소를 지정(프로세스 1이 명령 A를 호출)
- 프로세스 0이 데이터를 쓰기(프로세스 0이 명령 B를 호출)
3번 처리에서 데이터를 쓰고 싶었던 원래 장소는 1에서 지정한 장소이지만, 2번 처리가 끼어들어서 의도와는 다르게 2에서 지정한 장소에 쓰기가 실행되면서 원래 있던 데이터가 손상됩니다. 지금처럼 직접 저장 장치에 접근한다면 명령 실행 순서를 올바르게 제어하지 않으면 무척 위험합니다.
이런 문제말고도 장치에 접근 불가능이어야 할 프로그램이 장치에 접근하는 문제도 발생합니다. 이러한 문제를 해결하기 위해 커널은 하드웨어 도움을 받아 프로세스가 장치에 직접 접근하 룻 없도록 합니다.
PC나 서버에서 사용하는 일반적인 CPU에는 커널 모드와 사용자 모드 두 종류의 모드가 있습니다. 정확하게 말하면 CPU 아키텍처에 따라 세 종류 이상의 모드가 존재하지만 여기서는 자세한 설명을 생략합니다. 프로세스가 사용자 모드로 실행되고 있으면 사용자 공간에서 프로세스를 실행한다라고 합니다.
리눅스에서는 커널만이 커널 모드에서 동작, 프로세스는 사용자 모드에서 동작합니다. 프로세스는 장치에 직접 접근할 수 없으며, 커널을 통해서 간접적으로 장치에 접근합니다.
커널은 커널 모드로 동작하면서 다른 프로세스에서는 불가능한 장체 제어, 시스템 자원 관리 및 배분 기능을 제공합니다. 모든 공유 자원을 한 곳에서 관리하고 시스템에서 동작하는 프로세스에 배분할 목적으로 커널 모드로 동작하는 프로그램이 커널입니다.
시스템 콜
시스템 콜은 프로세스가 커널에 처리를 요청하는 방법으로, 새로운 프로세스 생성이나 하드웨어 조작처럼 커널의 도움이 필요할 때 사용합니다.
- 프로세스 생성, 삭제
- 메모리 확보, 해제
- 통신 처리
- 파일 시스템 조작
- 장치 조작
프로세스가 시스템 콜을 호출하면, CPU에서는 예외(exepthin)라는 이벤트가 발생합니다. 이를 계기로 CPU 모드가 사용자 모드에서 커널 모드로 바뀌고 요청 내용에 따라 커널 처리가 동작합니다. 커널 내부에서 시스템 콜 처리가 끝나면 사용자 모드로 돌아와서 프로세스 동작이 이어집니다.
시스템 콜 호출 확인해 보기
vi hello.go
-----------------------------------------
package main
import (
"fmt"
)
func main(){
fmt.Println("Hello,GO")
}
strace 명령어로 출력 결과 확인해 보자.
strace -o helloglog ./hello
cat hello.log
strace 출력 각각의 줄이 1개의 시스템 콜 호출입니다. 세세한 숫자 등은 무시하고 핵심만 보면 write() 시스템 콜로 "Hello,GO\n"이 출력합니다. 이때 실행시 209줄이 나와서 209번 호출되었습니다. go에 있는 main()함수 전후에 실행된 프로그램 시작과 종료 처리가 호출한 것입니다.
GO 언어뿐만아니라 다른 언어로 하여도 똑같은 시스템 콜이 작동합니다.
시스템 콜을 처리하는 시간 비율
시스템에 설치된 논리 CPU가 실행하고 있는 명령 비율은 "sar" 명령어을 사용하면 알 수 있습니다.
sar -P 0 1 1
-P 0 은 CPU 0의 데이터를 수집한다는 의미
1은 1초 마다 수집
그다음 1은 수집 횟수집 의미, 즉 지금은 1번만 수집
"inf-loop.go" 프로그램을 백그라운드로 실행하면서 sar 출력 결과 확인해 봅니다.
시스템 콜 getppid()를 무한히 발생시켜 사용자 모드 커널 모드를 반복해서 왔다갔다 하게 하여 CPU 상태를 확인해 보면 위처럼 "%user, %system"의 퍼센트가 나옵니다.
시스템 콜 소요시간
strace -T -o hello.log ./hello
-T 옵션을 사용하면 각종 시스템 콜 처리에 걸린 시간을 마이크로 초 수준으로 측정할 수 있습니다.
라이브러리
OS가 제공하는 라이브러리는 여러 프로그래밍 언에어서 다수의 프로그램에서 공통으로 사용하는 처리를 라이브러리로 합쳐서 제공하는 기능입니다.
프로세스가 라이브러리를 사용할 때 소프트웨어 계층은 아래와 같습니다.
C 언어는 국제 표준화 기구에서 정한 표준 라이브러리가 존재합니다. 리눅스에도 이런 표준 C 라이브러리가 제공되며, glibc를 표준 C 라이브러리로 사용합니다. 프로그램이 어떤 라이브러리를 링크하는지 ldd 명령어를 사용해서 확인합니다.
libc.so.6 표준 c라이브러리를 뜻합니다. ld-linux-x86-64.so.2는 공유 라이브러리를 로드하는 특별한 라이브러리입니다. OS가 제공하는 라이브러리 중 하나입니다.
Go언어는 동적 실행 파일이 아닙니다.
파이썬을 확인해 봅니다.
내부적으로는 C라이브러리를 사용하고 있습니다.
시스템 콜 래퍼 함수
libc는 표준 C 라이러리뿐만 아니라 시스템 콜 래퍼 함수도 제공합니다. 시스템 콜은 일반 함수 호출과 다르게 C 언어 같은 고급 언어에서 직접 호출할 수 없습니다. 아키텍처에 의존하는 어셈블리 코드를 사용해서 호출해야 합니다.
예를들어 x86_64 아키텍처 CPU라면getppid() 시스템 콜은 어셈블리 코드 레벨에서 다음과 같이 호출합니다.
mov $0x63, %eax
syscall
첫 번째 줄은 getppid()의 시스템 콜 번호를 eax 레지스터에 대입합니다. 두 번째 줄은 syscall 명령으로 시스템 콜을 호출하고 커널 모드로 전환합니다. arm64 cpu는 다른 어셈블리어를 사용합니다. libc 도움이 없다면 시스템 콜을 호출할 때마다 아키텍처 의존 어셈블리 코드를 작성해서 고급 언어에서 계속 호출해야 합니다.
이렇게 libc는 내부적으로 시스템 콜을 호출할 뿐인 시스템 콜 래퍼 함수를 제공합니다. 래퍼 함수는 아키텍처별로 존재합니다. 고급 언어는 준비된 시스템 콜의 래퍼 함수를 호출하기만 하면 끝납니다.
정적 라이브러리와 공유 라이브러리
라이브러리는 정적 라이브러리와 공유(동적) 라이브러리 두 중료로 분류할 수 있습니다.
#include <unistd.h>
int main(void){
pause();
return 0;
}
정적 라이브러리는 링크할 때 이 라이브러리의 이런 함수를 호출합니다. 동적 라이브러리는 실행 중에 라이브러리를 "메모리에 로드"하고 프로그램은 그 안에 있는 함수를 호출합니다.
코드 실행 후 두 가지 관점을 확인해 봅니다.
- 파일 크기
- 공유 라이브러리와 링크 상태
동적 라이브러리의 장점
- 시스템에서 차지하는 크기를 줄일 수 있습니다.
- 라이브러리에 문제가 있을 때 공유 라이브러리를 수정 버전으로 교체하기만 하면 해당 라이브러리를 사용하는 모든 프로그램에서 문제가 수정 가능합니다.
동적 라이브러리 컴파일 한 결과
libc.so.6 참조하고있다.
참고사이트:
linux 정적 컴파일 동적 컴파일
linux gcc에서 동적으로 컴파일 하는건 그냥 하면 되지만정적으로 컴파일하는건 -static 옵션을 넣어야 한다. 그럼 정적으로 컴파일 했을때 얻는 장단점은 무엇일까?원래 리눅스에서 동적으로 컴파
powerprove.tistory.com
'그림 리눅스' 카테고리의 다른 글
프로세스 관리(1) (0) | 2023.11.05 |
---|