240219

Yonggeun Park·2024년 2월 19일
0

루트 파일 시스템

Yocto Project : 임베디드 리눅스 빌드 프로그램 / 빌드 후 이론 수업을 하기로 했다
루트 파일 시스템 : 루트 폴더(최상위 디렉토리)에 부팅에 필요한 파일들을 모아놓은 것
실무에서 yocto를 많이 사용함

~/pi_bsp$ mkdir rootfs ; cd rootfs
~/pi_bsp/rootfs$ mkdir yocto ; cd yocto
~/pi_bsp/rootfs$ sudo apt update
~/pi_bsp/rootfs$ sudo apt-get install gawk wget git diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm python zstd liblz4-tool -y
~/pi_bsp/rootfs/yocto$ git clone -b kirkstone git://git.yoctoproject.org/poky.git

임베디드 파일 시스템은 크기가 작다

~/pi_bsp/rootfs/yocto/poky$ git clone -b kirkstone git://git.yoctoproject.org/meta-raspberrypi
~/pi_bsp/rootfs/yocto/poky$ source oe-init-build-env  // 경로들을 잡아준다
~/pi_bsp/rootfs/yocto/poky/build$ vi conf/local.conf

38 shift g
38번째 라인을 #으로 막고
39번째 라인에 MACHINE ??= "raspberrypi4" 를 추가한다

그리고

~/pi_bsp/rootfs/yocto/poky/build$ vi conf/bblayers.conf

12번 라인에 추가한다
/home/ubuntu/pi_bsp/rootfs/yocto/poky/meta-raspberrypi \
저장하고

~/pi_bsp/rootfs/yocto/poky/build$ bitbake core-image-minimal

굉장히 오래 걸린다

리눅스 커널

커널 : 운영체제의 핵심
리눅스는 모놀리틱 커널이다 : 커널이 운영체제가 관장하는 모든 서비스를 가짐
cpu가 성능이 우수해서 하나의 프로세스만으로는 아깝다
더 낮은 클럭의 mcu는 1개로 여러개를 조종할 수 있다
멀티 프로세싱을 하기 위해 cpu 속도는 더 빨라야함
그래서 운영체제가 필요하다
또, 메모리 관리, IPC(프로세스간의 통신/signal,pipe,socket,message Queue),
virtual file system : 파일 일부분을 메모리처럼 사용 (스왑, 디바이스를 파일처럼 취급)

프로세스 스케쥴러

  • 커널 타이머 / f=250Hz T=4ms (라즈베리는 100Hz)
~/pi_bsp/kernel/linux$ vi .config  // 이런식으로 볼 수 있다

  • CPU를 여러 프로세스가 공평하게 사용할 수 있도록 한다

네트워크 인터페이스 : 표준 네트워크 프로토콜과 드라이버 제공

프로세스

프로세스

  • 실행중인 프로그램
  • 구성 : 프로그램/데이터RW/스택/프로세서 내부의 pc를 비롯한 레지스터와 상태 정보

멀티 프로세싱

  • 동시에 여러 프로세스가 활동

프로그램이 아님

  • 여러 개의 프로세스가 하나의 프로그램을 동시에 실행 가능
  • 프로세스 하나가 여러 프로그램을 차례로 실행 가능

스케쥴러

한 순간에 오직 하나의 프로세스만이 CPU 점유 가능

  • 커널 Hz에 해당하는 만큼 권한 있음. 보통 4~10ms

선점형/비선점형

  • 선점형은 시간을 지켜보면서 스케쥴링
  • 비선점형은 cpu 사용권 반납했을때 스케쥴링, 프로세서 내에선 비선점형

Context switch

  • cpu의 사용권을 다른 프로세스에게 양도
  • 현재의 context 정보를 저장하고 새 프로세스의 context 정보를 적재
  • PC, SP, 범용 레지스터, 상태 레지스터 등이 있다

리눅스의 프로세스 스케쥴링

  • time slice(각 프로세스가 실행되는 최소한의 실행 단위)가 끝나면 다른 프로세스 실행
  • RR과 FIFO 방식의 알고리즘

Task structure

  • state : 현재 상태
  • 정보 : 공정한 스케쥴링을 위한 정보
  • 프로세스ID : 각 프로세스가 가지는 user 또는 groupID
  • IPC : signal, pipe 등 IPC정보
  • links : 부모자식 프로세스 정보

State of Process

  • running : 실행 및 실행준비 완료
  • waiting : 이벤트를 기다림
  • stopped : signal에 의해 정지됨
  • zombie : 비정상적인 halt, 많으면 안됨

fork
새 프로세스 생성 시 부모 프로세스 정보를 메모리 공간에 복사
-1이면 에러
0이면 자식
나머지는 부모 이다.
exec : 프로세스를 교체하여 실행
실습으로 확인한다

~/pi_bsp/kernel$ vi fork.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int fatal(char *s);
int main(void)
{
    pid_t pid;
    switch(pid=fork()){
        case -1:
            fatal("fork failed");
            break;
        case 0:
            execl("/bin/ls", "ls", "-l", NULL);
            fatal("exec failed");
            break;
        default:
            wait((int *)0);
            printf("ls completed\n");
            exit(0);
    }
}
int fatal(char *s)
{
    perror(s);
    exit(1);
}


ls -l 명령어랑 동일하다
execl을 만나는 순간 자식 프로세스가 생성되어 프로그램이 달라진다
그래서 fatal 문을 실행하지 않고 ls -l만 실행되고 종료된다
그리고 wait에서 결과를 받고 ls completed가 실행된다

자동으로 왼쪽으로 8번 쉬프트 되므로 출력할 때는 오른쪽으로 8번 쉬프트한다


이렇게 없는 폴더를 넣어주면

정상적으로 ls는 실행되고 없다는 에러메시지가 perror를 통해 나온다
만약 wait를 없애면 좀비프로세스가 된다

커널 쓰레드

~/pi_bsp/kernel$ ps -ef | more

명령어로 커널 스레드를 볼 수 있다
시스템 관리를 위한 백그라운드 동작이다
rc5.d에 여러 데몬들이 있다

PID 모든 프로세스는 PID를 가진다
파일을 문자열로 구분하지만 시스템은 숫자로 기억한다
ls -i 하면 번호가 나온다(i nod 구조)

pstree 하면 프로세스 구조가 나온다

exit는 자기 자신을 종료
abort, kill은 부모에 의해 강제적으로 종료

메모리와 주소

  • 메모리 : 프로그램과 데이터(변수)를 저장하는 공간, 물리적 주소를 사용하여 지정(8비트)

  • 메모리 사이즈에 따라 주소가 고정됨

  • 논리주소=선형주소 : 가상주소 라고도 함 / 1기가까지 커널, 3기가까지 사용자가 사용, 4기가까지 가능 / 부족한 메모리를 가상으로 할당 - MMU table에서 가상과 물리를 매핑함

  • 물리주소

  • 내가 할당받지 않은 메모리 공간에 접근하면 exception-segmentation fault

  • 개별 주소 사용

  • heap(동적 영역) malloc으로 메모리 할당 후 free로 반환

  • 시스템 콜 mmap app을 이용하면 실제 하드웨어 주소공간에 어플리케이션에서 공유하도록 지정
    디바이스 드라이브 구현해야함

  • 리눅스의 메모리 관리
    - 큰 주소 공간 사용 : 가상메모리로 더 큰 메모리 공간을 가지고 있는 것처럼 사용 가능
    - 메모리 보호 : 가상메모리를 사용할 수 없는 경우 다른 프로세슷는 동일한 메모리공간을 참고 불가능
    - 메모리 매핑
    - 공유 메모리를 여러 프로세스가 공정하게 사용
    - 프로세스 간 메모리 공유를 위한 방법 제공
    물리 주소 공간의 조각화
    세그멘테이션과 페이지는 물리 주소 공간을 쪼갠다
    4k로 쪼갠다

Demand paging : 필요할 때마다 메모리에 할당
COW(copy on write) : 자식 프로세스 생성 시 공유된 프레임에 쓸때 페이지 프레임을 복사
스와핑 : 디스크의 일부 공간을 램의 확장으로 사용

  • 스왑아웃 : 주소공간을 디스크에 복사
  • 스왑인 : 디스크에서 프로세스를 가져옴

프로세스간 통신

p1 - p2 데이터 주고 받으려면
프로세스간 통신을 사용
IPC
read() : blocking 함수
멀티프로세스 기반 다중서버 하려면 서버를 fork 하고 복제된 것과 통신을 한다
또 다른 클라이언트와 연결할 때 서버를 복제해서 1:1 통신을 하게된다
클라이언트가 늘면 늘수록 cpu 입장에서 보면 메모리를 많이 할당 받는다
그런데 클라이언트끼리는 연결이 안돼서 각각의 복제된 서버 프로세스들끼리 연결을 하는데 그것이 바로 IPC이다

  • 시그널, 파이프, 소켓, 메시지 큐, 세마포어, 공유메모리가 있다

전역변수를 지정하면 하나의 프로세스에만 써야한다 만약 다른 프로세스가 접근하면 락을 걸어서 못오게 막아야한다 대신 큰 하나의 프로세스로 만들어서 락언락을 적용하면 하나 고장나면 다 못쓴다?

시그널

실습

pi를 킨다
켜놓고 우분투에서

~/pi_bsp/rootfs$ wget https://downloads.raspberrypi.org/NOOBS_latest

근데 용량이 너무 커서 복사받기로 했다
그 전에 너무 번거로운 복사과정때문에 우리의 ubuntu와 교수님 ubuntu를 mount 하기로 했다

-교수님-
/srv$ sudo mkdir lect_nfs

-나-
vi .profile

맨 아래에

if [ -f /mnt/nfs.sh ] ; then
    . /mnt/nfs.sh
fi
그리고 /mnt$ sudo vi nfs.sh

들어가서

#!/bin/bash
SERVIP=10.10.15.71
if ! df | grep lect_nfs > /dev/null ; then
	ping -c 1 $SERVIP > /dev/null
	if [ $? -eq 0 ] ; then
			sudo mount -t nfs $SERVIP:/srv/lect_nfs /mnt/lect_nfs
			df | grep lect_nfs
	fi
fi
저장한다

source nfs.sh 실행하면 mount 된다

~/pi_bsp/rootfs$ unzip -d noops NOOBS_latest

~/pi_bsp/rootfs$ cd noops/os/RaspiOS_Full_armhf/


이것이 루트 파일 시스템이다

~/pi_bsp/rootfs$ mkdir rootfs
~/pi_bsp/rootfs$ sudo tar xvfp root.tar.xz -C ./rootfs
압축을 푼다

계정을 하나 만들 것이다

~$ sudo adduser pi
~$ cat /etc/passwd



내가 입력한 내용이 들어가있다

~$ sudo cat /etc/shadow하면 맨 아래에 pi에 대한 내용이 있는데

~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf/rootfs/etc$ sudo vi  shadow에

pi:$6$0L5suchDSQEs1t/h$ImQpaW7NLS0LYNZfq3BW7ywwTH/KiwGXvC0NDoFhs3NEZa.1VArld4y76gPnN2y3uQEFBYhSkbPTvqh/bbiJQ.:19772:0:99999:7::: 를 복사한다

그리고 복사하기 위해 다 지운다

~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf/rootfs$ sudo rm -rf /media/ubuntu/rootfs/

이제 다시 복사한다
~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf$ sudo cp -ra rootfs/* /media/ubuntu/rootfs/.
a는 원본 파일의 속성, 링크 정보까지 모두 복사한다는 뜻
~/pi_bsp/rootfs/noops/os/RaspiOS_Full_armhf$ sudo blkid

/media/ubuntu/rootfs$ sudo vi etc/fstab
ced3dfde 이거로 수정해준다(사람마다 다름)
/media/ubuntu/rootfs$ cd ../bootfs
/media/ubuntu/bootfs$ sudo touch ssh

이후 umount 해준다
SD카드 제거 후 라즈베리파이에 넣고 다시 킨다

아이피가 바뀐 모습

다시 우분투에서

~$ cd pi_bsp/rootfs/yocto/poky/build/tmp/deploy/images/raspberrypi4/
~/pi_bsp/rootfs/yocto/poky/build/tmp/deploy/images/raspberrypi4$ ls -l *.ext3


12메가짜리 아주 작은 루트 파일 시스템이 만들어졌다

$ cp 
~/ipc$ gcc sigloop.c -o sigloop
~/ipc$ ./sigloop

이 상태에서 ctrl+c를 눌러도 종료가 안된다! -> kill 해야함

~$ sudo kill -9 2472443(다른 창으로)
-9 : 매우 강력하게

~/ipc$ vi sigloop.c


SIGINT : ctrl+c

~/ipc$ ./sigloop
~/ipc$ ps auwx | grep sigloop(창 여러개로)


s+ : sleep
pause : signal에 의해 깨어나는 함수

이렇게 수정해서 ctrl+c 누르면 2초마다 알람주는 코드로 바꿨다

그리고 sigkill.c를 본다

~/ipc$ ./sigloop
~/ipc$ gcc sigkill.c -o sigkill
~/ipc$ ./sigkill 2472947 2


sigkill에서 sigloop로 통신을 한 것이다(IPC)

if(signo == SIGINT)
{
    printf("Catch SIGINT!, but no stop%d\n", signo);
    exit(0);
}
이렇게 종료 조건을 넣으면 ctrl+c 눌렀을 때 종료된다

profile
Dragon_muscle

0개의 댓글

관련 채용 정보