Bullshitting Blog

개소리하는 블로그

Burst mode

심리검사결과에서 이야기한 것처럼, 난 지금 경조증 상태다. 그래서 액터 라이브러리의 업데이트가 일주일 사이에 메이저로 4번이나 이루어져 버렸다. 물론 메이저 업데이트를 과감하게 하기 때문에 생각하는 만큼의 코드작업은 아니지만, 개선이 빠르게 이루어진건 사실이다.

6.0.0은 액터 간 통신 시 직렬화를 제거해서 성능을 확보했다. 직렬화만 제거한게 아니라, 메시지 자체를 래퍼런스만 전달하게 해버려서 극단적으로 성능이 향상됐다.

7.0.0은 bounded-channel 지원을 추가했다. 적당히 await하도록만 추가했지만, 백프레셔 상황에서 OOM이 나는건 막게 됐다.

8.0.0은 ActorSystemCmd enum member들의 각 요소에 이름을 달기 위해, 멤버들을 구조체로 변경했다. ActorSystemCmd를 직접 tx 받아다가 쏘는 유저 때문에 메이저 업데이트로 뒀다.

9.0.0은 job 기능에서 abort/stop/resume이 가능하도록 추가했다. 물론 잘 쓰이진 않는 피쳐인 듯 하지만, job이 있다면 그걸 컨트롤할 수도 있어야 할 것 같아서 추가했다.

그리고 사실 9.0.0 기능의 stop/resume의 세부 동작에서도 개선할 부분이 남아 있는데, 너무 달리는 것 같아서 일부러 멈춘 상태이다. 게다가 안쓰잖아요? 난 쉽니다.

그럼 이 코드 작업 안하고 뭘 하는가 하면... 역시나 쉬진 못하고 있다. 그래도 잘 땐 잠이 온다. 그조차도 감지덕지다.

심리검사 결과

불면증으로 인해 병원에 방문했다. 하지만 몇 차례의 진료 과정에서 심리 문제임이 의심되어 심리 검사를 풀세트로 받게 되었다.
최근 회사에서 큰 스트레스를 받을 사건이 있었던 후 불면증으로 병원을 찾았던 것인데, 안정제를 처방받았더니 평일에도 내리 10시간 이상씩 매일 잠을 자고, 주말엔 하루 종일 잠을 잤다. 이후 항우울제를 극소량 복용했더니 말도 안되는 몰입력으로 하루 종일 집에 홈랩을 구축해댔다. 수면 시간도 확 줄어들었다. 그 사실을 알리니 의사는 조울증을 의심하기 시작했다. 항우울제를 빼고 조울증 약을 먹기 시작하면서 조금 나아졌다. 대신 이번엔 수면이 분절됐다. 매일 새벽 2시, 4-5시에 깬다. 4-5시에는 너무 쌩쌩해서 정말 일과를 시작해야 하나? 하고 밥을 먹거나 컴퓨터를 하다 보면 다시 1시간쯤 후에 졸려서 다시 자야 한다. 그걸 반복하고 있다. 그래서 결국 심리검사를 받게 됐다. 임상심리상담가(?)가 와서 그림도 그리라고 하고, 데칼코마니 보여주면서 보이는거 이야기하라고도 하고 그랬다.
결과는 너무 길다. 다 쓰기 귀찮다. 다만 특징적인 부분은, 내가 스트레스 상황이 있으면 일에 몰입하는 방식으로 그 불쾌함을 잊는 경향이 있다는 것이다. 심각한 조울증이라기보다는 그쪽 영향이 컸던 것 같다. 지금은 경조증 상태로 보인다고 한다. 스트레스 상황이 아직 끝나지 않았기 때문인 듯 하다. 회사 자체가 스트레스인 상황이다. 하지만 피할 수 없다. 피하기도 싫다. 지는 것 같기 때문이다. 그냥 시간아 빨리 가라 하고 일에 몰입하고 있다. 항상 그랬듯이 말이다.
아, 정신 문제? 모든 지각능력이 정상이라고 한다.
어쨌거나 저쨌거나, 운동이나 해야 할 것 같다. 근력 운동을 시작하긴 했지만, 주에 1-2회밖에 안하는 상황이다. 피곤하면 바로 스킵하고 있다. 하지만 일로 도피할 에너지를 좀 더 여기다 써도 될 것 같다. 날이 풀리면 조깅도 시작할 것이다. 무엇보다도, 상황이 좋아지고 병원 도움도 받게 되면서 식욕이 되돌아왔다. 그래서 하루 6번 매일 똑같은걸 끊어먹던 생활에서 탈피해서 3끼로 줄었고, 2끼를 든든하게 먹게 됐다. 무려 일반식으로 말이다. 그와중에 하는 운동은 가끔 하는 근력 뿐이니, 벌크업만 된다. 그래서 지금 71kg이다. 역대급 몸무게다. 무릎이 "뭐야 무슨 일이야!?" 하고 소리치고 있다.

액터 메시지 송신 시 직렬화 제거

말만 들어도 성능 떨어질 것 같은 피쳐다. 그동안 개발 편의성에 중점을 두기 위해 여러 메시지 타입을 지원하도록 하려고 직렬화를 이용했다.
결론만 공개하면, 여러 메시지 타입을 지원하는건 그대로 가져가면서 직렬화를 제거했다. xan-actor 6.0.0

근데 그 작업을 내 머리로 했을까? 아니다. 난 지금 건강 문제와 함께 터진 번아웃으로 인해 머리가 전처럼 안돈다. ChatGPT 과금해서 쓰고 있는데, Codex가 있길래 써봤다. 이녀석은 dyn trait을 Arc로 감싸서 컴파일 타임에 타입의 크기를 알 수 있게 우회하는걸 실제로 해줬다. 컨택스트 유지하는 비용이 큰 그 작업을 말이다.

아무래도 과거 손가락이 부러져서 코파일럿과 합을 맞춘 것처럼, 이번엔 뇌가 부러졌(?)으니 codex든 claude든, 코딩 에이전트와도 합을 맞춰가야 할 듯 하다. 주변에 claude를 아주 잘 쓰시는 분이 있는데, 그 분이 평하시기로는 codex는 보수적인 편이고, claude는 적극적인 편이라 했다. ChatGPT만 사용중이라서 선택지는 없긴 하지만, 사실 보수적인걸 좋아한다. 그냥 가자.

귀찮아서 모니터를 없앰

집에서 노트북에 24인치 모니터를 연결해서 쓰고 있었는데, 슬슬 귀찮아짐.
무엇보다도 모니터 거치대의 높이에 한계가 있었는데, 노트북 모니터도 높이를 좀 올리고 싶었음. 그랬더니 의자를 제껴서 누워서 보면 노트북 모니터가 외장모니터 일부를 가려버렸다.

그리고 오늘 본격적으로 킹받는 부분이 발생했다. 집 조명이 애매한 밝기인데, 교체가 귀찮았음. LED
라서 전등 패널 자체를 통째로 교체해야 하기 때문이다. 게다가 교체한다고 해도 밝아진다는 보장도 없음. 그래서 모니터 밝기를 조절하기로 하고 ddcutil을 설치함. 그리고 신나게 ddcutil detect를 날림. 그 결과, 모니터는 DDC/CI를 지원하지 않음. 그래서 새 모니터를 사야 한다.

개뿔? 왜? 그냥 모니터를 없애면 되는거 아님? brightnessctl 이용하면 내장모니터 밝기 설정은 가능함. 그래고, 리눅스 유저로서 작은 화면에서 아무 것도 못하는 것은 수치다. 그냥 13인치 노트북 모니터에 적응하기로 함. 모니터를 당장 연결 해제하고 창고에 넣어버렸다. 넣고 나니까 책상도 훨씬 깨끗하고 좋다.

남은건 작은 화면인데, 워크스페이스가 10개나 되는데 불평할꺼면 그냥 포기하고 커다란 모니터 사서 윈도우나 쓰자. 맥은 선택지에 없냐고 묻는다면, 개인적으로 맥 별로 안좋아한다. 플랫폼에 종속되게 만드는거 극혐이다.

홈랩에 빠져드는 중

회사에서 NAS의 동작 방식을 접하고 나니 NAS를 직접 구축해버리자는 뽐뿌가 와버렸고, 결국 질러버렸고, 결국 해버렸다.
그저께는 UTP케이블의 끝단을 잘라서 랜툴로 straight 케이블을 제작했는데, 아니 이게 너무 재밌지 않은가. 결국 랜툴과 플러그, 거기에 UTP 케이블 100m까지 구매해버렸다.
돈이 많이 드는 취미다. 일단 노트북을 유선으로 쓰자는 목표까지만 달성하면 다시 개발로 돌아가야겠다.

Talos Linux 클러스터 올리기 성공

몇 번의 포기와 번뇌와 회귀 끝에 성공했다.
결론부터 공개하면, Talos iso 이미지를 빌드하는데 사용했던 Schematic ID가 아주 중요했다. 이걸 machingconfig의 installer image에까지 반영해줘야 했다.
그렇지 않으면 extra extensions가 없는 깡통 talos가 설치되는 것이다.

다음은 그래픽카드가 문제였다. 원랜 gpu-operator를 올려서 모든걸 설치하지만, 여기선 투머치. nvidia-device-plugin만 올리면 됐다.
어떻게 하는지는 github에 다 올려놨다.

NAS를 만들다가 일어난 일

HDD 4개를 사서 윈도우 깔아둔 노는 게이밍PC를 NAS로 탈바꿈하기로 했다.
사다가 뚜껑을 열었다. 메인보드에선 SATA 4개는 당근 지원한다. 하지만 케이스는 아니다.
HDD 확장 슬롯을 사다가 연결했다.

회사에서 팀장님이 추천해주신 방법은 Proxmox를 설치한 후 NAS조차 가상머신으로 관리하는 것이었다. 유연하다는 것이 그 이유였다. 좋다. 가자!
Proxmox를 설치했다. 그리고 가상머신을 만들어서 OpenMediaVault를 설치했다. 근데 RAID로 하드 엮은 후 resync는 왜이래 오래 걸리는지.... 기다리다가 결국 또 튀었다.
기존에 클러스터 올리던 Arch Linux 머신도 밀어버리고 Proxmox를 깔았다. 그리고 목표를 다시 잡았다.

topology-objective-final.png

지금은 저걸 1차로 다 하면서 Talos Linux에 도전했다가 GPU passthrough 후에 rustcost-gpu-exporter를 동작하게 하는데 실패했다. 참여중인 오픈소스인데, 의외의 장벽에 부딪혔다. 쉘이 없다는게 이렇게 클 줄이야. rustcost-gpu-exporter는 내부적으로 nvidia-smi를 호출한다.
그래서 다시 탈탈로스 하려는 바이다.

KVM K8S 클러스터 대충 완성

회사에선 사용성 높은 RKE2를 이용해서 Ubuntu 머신에 쿠버네티스 클러스터를 운영한다.
하지만 집에선? 깡으로 간다. 항상 그 깡으로 가는 방식을 실제로 해보는게 실제로 습관이자 취미이다.

결과물은 여기에 있다. 세팅이라는 행위 자체가 무한 삽질이므로, 단계별로 스크립트를 짜면서 삽질을 한다. 그래서 VM까지 다 통째로 날리고 다시 테스트하는 짓을 해도 20분 걸린다.

home-cluster

What or Why

VM

자 그럼 일단, 그 KVM이 뭔가? QEMU는 또 뭔가? 간단히 말하면, VM을 만들어주는 녀석은 QEMU, 거기다가 각종 커널 인터페이스를 제공해주는 녀석이다.
이렇게 설명할거면 뭐하러 설명을 하냐. 그냥 문서 찾아보라고 하지.
쉽게 설명해 보겠다.
조립컴퓨터를 만든다 치자. 신나게 부품을 사다가 가지고 왔다. 케이스에 메인보드와 파워를 체결한다. 이게 QEMU가 해주는 역할이다.
이제 메모리를 꽂고, cpu를 꽂고, gpu도 꽂아보자. 그게 KVM이 해주는 역할이다.

쿨러 등은 생각하지 말자.

KVM은 그 cpu, mem, gpu 자원을 호스트에서 실행하게 해주고, 커널은 호스트의 것을 사용하게 한다. 물론 격리된다.

그런데 QEMU도 단독으로 사용 가능하다. 내장된 기능이 있다. 게다가 이건 다른 아키텍쳐도 실행이 가능하다. arm이라던지 말이다.
너무 좋잖아? 세상 너무 대단하다.

Network

GPT 선생은 bridge를 강력 추천했다. 그래서 NAT로 구성했다. 박진감 넘치는 미래가 예상된다. 물론 현재도 박진감 넘쳤다. 나중에 그림이 하나 나올건데, 서버에서 포트포워딩을, 노트북에서 라우팅 설정을 하다가 포기한 결과다. 라우팅만 해결하면 되는거같지만, 사실 더 있다. modprobe, sysctl도 건드렸다. 그래도 안됨. 결국 dns가 문제였다. 커맨드라인에서 dig까진 성공했으나, 웹에서 포기함. 근데 또 언젠가 또 오기 생기면 이거 파고 있을 예정이다.

Alpine

VM의 OS는 Alpine을 선택했다. 경량 하면 Alpine이다. glibc조차 없다. 대신 musl 라이브러리를 사용한다.
호환성? 당연 개구리다(개굴개굴 노 멍멍 예스). libtorch 이용도 안된다. 물론 어찌저찌 붙인 적은 있는데, 실제로 잘 돌지는 모름.
근데 왜 사용하냐 한다면, 이것도 그냥 취미다. 안된다는거 골라서 다 해보는 것 말이다. 근데 그런걸 회사에서 할 수는 없으니, 집에서 푸는거다.
아 물론, GPU 노드는 ubuntu server minimal로 깔았다. libtorch는 glibc가 없으면 안돈다. 물론 학습 돌릴 것은 없지만 말이다.

Kubernetes with kubeadm

RKE2를 한 번 써봤더니, 그 편함에 잠시 약해졌다. 게다가 1.26버전이 나오던 시절에 쿠버네티스와 잠시 이별을 했었기 때문에, 오랜만에 사용하니 보안성 강화를 위해 kubeadm 사용이 조금 복잡해졌다. 뭐 어쨌든, 다시 강해지도록 하자 ㅋㅋ.
과거 kubespray라는 툴이 있었고, 실제로 사용법도 배웠다. 하지만, 폐쇄망 기반에 보안팀이 강력한 고객사에서 클러스터를 운영하려니 스택이 많을 수록 더 어려워져서 결국 kubeadm이 가장 좋은 선택지였다. 그냥 이미지랑 바이너리를 미리 파일로 말아서 가져가면 되는 일이었기 때문이다(우린 이미지를 빌드하거나, 패키징을 하는 행위를 "말다"로 표현했다).

Bind

DNS 서버 구축하기 위한 아주 오래된 스택이다.
문법도 지랄맞다. 암기과목이다. 하지만 요즘은 GPT라는 집단지성 하드디스크가 있으므로, 오히려 이런 오래된게 더 편함.

HaProxy

로드밸런서이자, Proxy이다. 회사에서 써보고 감탄했다. dns 세팅은 간단히 해버리고, proxy에서 왠만한건 다 라우팅해버린다. 여기다 인증서 반영해 두면 https도 알아서 지원된다. control-plane 노드를 3개 구성한 후 이걸 어떻게 분산해서 쓰는가에 대해 답을 주는 녀석이다. 물론 virtual ip를 이용하는 방법도 있는데, 이건 스위치랑 라우터 등등 네트워크 장비와 싱크가 안맞으면 지옥을 맛본다.

How

아 이게... 설명하기가 정말 귀찮다. 다 스크립트 만들어 뒀고 실행하면 되는데 그걸 설명하는건 정말이지...
그래서 RTFM을 시전한다. README에 다 있다.
무슨 짓을 한 것인지는, 그림을 첨부하겠다.

원래 목표

topology-objective.png

현재 상태

topology-current.png

현재 목표=원래 목표

Next

NAS 서버를 직접 만들어 볼 것이다. 부품은 다 왔는데, GPU passthrough 한다고 삽질하느라 많이 지체됐다.

공포의 대상보다 공포의 영향이 더 위험하다.

공포 마케팅은 한국에서 가장 잘 통하는 마케팅 중 하나이다. 미래를 대비하지 않으면 큰일이라도 나는 줄 안다. 가만히 있으면 도태되는 줄 안다. 그러면서 자신은 지금 무엇을 하고 있는지 모른다. 그저 시간을 흘려보낸다. 새롭고 획기적인 것을 찾아 불나방처럼 돌아다니기도 한다. 공포 마케팅을 하는 대표적인 업계는 사교육, 그리고 헤드헌팅 업계이다.
하지만 성장은 눈에 보이는 성과에서 오는 것이 아니다. 지난하고 지루하고 반복적인 훈련을 통해 오는 것이다. 성과는 그것이 한 번씩 드러나는 과실에 불과하다. 사과나무의 본체는 나무이지, 사과가 아니다.

ChatGPT? 그녀석은 그냥 부하 직원같은 존재다. 게다가 머리가 애매하게 좋은 녀석이다. 리더가 얕보이는 순간 그놈은 리더를 속이려 들 것이다. 지식에 대한 지능은 높지만 사회지능이 없거나 낮은 인간의 특성과 동일하다. 물론 그녀석이 매니저를 대체할 수는 있겠다. 그 윗 라인을 속여먹으려 들지만 않는다면 말이다.

그럼 우리가 해야 할 것은 명확하다. 그리고 바뀐 것이 전혀 없다. 우린 이미 정보화사회에서 가장 중요한 것은 사실과 거짓을 판별하는 능력이라 배웠다. 그것은 바뀐 것이 없다. 그걸 하기 위해서는, 머리를 쓰는 능력 자체를 길러야 한다. 단편적인 지식은 당장은 진리같아 보여도, 실제로는 일회용품에 가깝다.

문제의 그 AI라는 녀석은, 지금 특히 프로그래머들에게 공포의 대상이다. 그 외 여러 직군들도 마찬가지인 듯 하지만, 요바닥은 거의 집단 우울증에 걸린 듯한 모습이다. 뭐해먹고 사나에 대한 이야기를 많이 듣는다. 하지만 난 확신한다. AI의 희생자가 될 사람은, 실제로 AI에게 먹혀서가 아니라, AI에 대한 공포에 휘말려 스스로 포기한 사람들일 것이다. 결국 남은 사람들은 그 AI라는 녀석을 써서라도 생산성을 몇배나 더 향상시킨 상태로 그들의 빈자리를 유지해야 할 것이다. 채용이 줄어들 것은 뻔한 양상이기 때문이다.

난 과거 파쿠르를 했었다. 꽤나 몰입했었다. 2012년부터 2017년까지 했었다. 당시엔 원류의 철학이 대세였던 시절이었다(훈련도 지옥훈련이었다 ㅋㅋ). 내가 파쿠르 철학 중 깊히 새긴 것은 아래와 같다.

  1. 유용하기 위해 강해져라.
  2. 다같이 시작해서 다같이 끝낸다.
  3. 넘어지는게 두려우면 그 두려움 때문에 넘어지게 된다.

현대의 AI에 대한 공포에 대해 대답해줄 수 있는 것은 3번이 아닐까 싶다. 그리고 살아님기 위해서는 1번과 2번을 실천하면 된다. 물론 2번은 사람에 따라 의아할 수도 있겠다. 하지만, 파쿠르철학에서 2번은 생각보다 구체적이고 일리가 있다. 사람마다 강점과 약점이 다 존재한다. 결국 가능하다면, 모두가 함께 가야 한다. 누군가는 낮은 담을 잘 넘고, 누군가는 높은 담을 잘 넘는다. 누군가는 체구가 작아 좁은 틈을 잘 비집고들어가고, 누군가는 힘이 좋아 도약을 위한 발디딤을 도와줄 수도 있다. 누군가는 그 사람들을 화목하게 유지시키기도 한다. 모두 능력이다. 높은 담을 넘을 때, 발디딤을 도와주면 말도 안되는 높은 담에 오를 수 있다. 그 사람은 거기서 다시 밑에 있는 사람을 잡아줄 수 있다. 그 도움을 받은 사람은 담을 못오르는 사람을 잡아줄 수 있다. 도약을 도와준 사람도 마찬가지로 담을 오르게 된다.

장애물은 낮은 펜스만 있는게 아니다. 낮고 넓은 장애물도 있고, 높고 얇은 장애물도 있고, 높고 넓은 장애물도 있다. 울퉁불퉁하기도 하고, 미끄럽기도 하다. 그건 내가 바꿀 수 없다. 그냥 거기에 있다. 그냥 저기서 나타난다. 심지어는 갑자기 달려드는 자동차도 하나의 장애물이다. 장애물이 원하는 모양이 아니라 해서 그걸 탓하면, 그것이 바로 당신이 그렇게도 무서워하는 도태의 지름길이다.

블로그 제작이 너무 쉽다

Notion에 일기마냥 글을 쓰고 있었는데, ChatGPT의 "다 들고와 뭐든 만들자!" 하는 성향 덕분에 블로그가 탄생했다.
깡 html, js, css로 그냥 끝나버렸다.
마크다운도 그냥 갖다쓰면 된다.
글? vim 쓰는 사람이 웹에 에디터 붙일 필요가? 없다.
만족이다.

친절한 블로그는 절대 아니다.
내가 기억하기 위한 일기일 뿐이다.
그래서 링크도 공개 안했다.

유저 트레킹도 안한다.
내가 싫어하는데 남한테 할 이유가 없다.
사실 귀찮은게 더 크다.
겸사겸사 배려의 차원인걸로 포장해 봤다.

부서이동 후기

ML Platform 팀으로 이동했다. 지금은 인수인계를 받고 있는 단계다. 이동한 팀의 팀장님이 이직을 하는 바람에, 기존에 계시던 분이 팀장으로 승진하면서 문서 정리와 동시에 실무까지 도맡으면서 인수인계 일정이 조금 길어지고 있다. 물론 아직 3일밖에 안됐다. 일단 빠르게 잡다구리한 일이라도 분담해야 할 것 같다. 과중한 상황을 겪어봐서 알기 때문이다. @!#$!#@!#@

일단 인수인계 준비하시는 것을 기다리면서, 쿠버네티스 개발환경 구축하는 과정을 따라가고 있다. KVM + QEMU 기반으로 로컬에 클러스터를 올리고 있다. 24스레드 머신이라 다행이다. 오늘 일단 클러스터 올리는 것은 다 마무리되었다. 하지만 GPU를 VM에 할당하다가 다 어그러졌다. 일단 재부팅을 해뒀고, 내일 더 볼 생각이다. 안되더라도, 손이 엄청 빨라졌기 때문에 딱히 걱정 없다.

오랜만에 쿠버네티스를 만져서 기억이 안날까 좀 걱정이었는데, 머리가 아닌 손이 기억하고 있었다. 내 생각에, 난 머슬메모리 용량이 뇌용량보다 큰 듯 하다. 아니, 뇌가 근육으로 이루어져 있는건가. 그리고 이번에 KVM + QEMU 조합을 처음 써봤는데, 커맨드라인으로 VM 관리 다 하니까 쾌감이 있다. VirtualBox는 커맨드라인에서 사용하면 아주 불편한데, 이건 아니다. 그냥 kubectl 쓰는 느낌이다. virsh edit <vm_name> 하면 그냥 XML 직접 수정이 가능하다. 내가 좋아하는 뺨 쎄리며 개발하는 그 느낌 맞다. 내 전공인 체육교육학을 영어로 쓰면 Physical Education인데, 물리적 교육이다. 맞다. 때려서 길들이는거다. 딱 대.

속지 마라.

또 한 가지, 관심 직무를 각자 이야기했는데, 정말 운이 좋게도 각자 다 달랐다. 난 고전적인 인프라 엔지니어링과 보안에 관심이 있다. 새로 입사하신 분은 클라우드에 관심이 있다. 팀장님이 이직하는 바람에 갑자기 신생팀처럼 된 면은 있지만, 그래도 관심사에 빈틈은 없는 듯 하다.

뚫었다 용인

그렇다 뚫었다. 그것도 용인의 내가 자주 가던 필드인 용인대학교를 찍는데 성공했다. 내비게이션 안찍고 말이다. 물론, 이번에도 용인의 어디를 갈지는 미정이였다. 심지어 이 상태는 용인에 도착한 이후에도 미정이었다. 용인시청 표지판이 보일 때까지 목적지를 몰랐다.

저번의 실패를 교훈삼아, 이번엔 섵불리 경기도 지역을 향한 표지판을 따라가지 않기로 했다. 저번에 실패했던 이유는, 안양 표지판이 보여서 섵불리 빠졌다가, 서부간선지하도로를 타게 됐고, 이후 복잡한 길에서 방향을 잃고 대충 시흥을 향했던 선택이 틀렸기 때문이었다. 이번엔 올림픽대로에서 좀 더 동쪽으로 갔다. 그러다 어항 모양 안에 1번이 적힌 표지판을 봤다. 1번이니까, 경부선 아닐까? 하고 따라가니 경부고속도로였다. 과거 용인으로 다닐 때도 경부고속도로를 종종 이용했었다.

경부고속도로를 타고 가다 보니, 용인서울고속도로가 나왔다. 바로 빠졌다. 그리고 종점까지 감. 그럼 용인이겠지. 그리고 나서는, 갈림길이 있었다. 갈림길에서 어디로 가야 하는지 확실히 모르는 상황이었는데, 신갈이 보였다. 용인과 신갈이 표지판에서 같은 방향으로 붙어있는 경우가 많았던 것을 떠올렸다. 그래서 신갈을 따라갔다. 물론 중간에 잘못 빠져서 한 바퀴 돌고, 난리도 아니였다.

신갈을 따라가다 보니, 용인시청 표지판이 나오기 시작했다. 오! 목적지는 용인대다! 용인시청을 향해 쭉쭉 따라가다가 용인대에 도착했다.

이제 남은건 돌아가는 것. 근데 방광을 비워야 한다. 다이소에 가서 화장실 들르는 김에, 감자칼을 샀다. 사야지 해놓고 까먹었던건데 마침 눈에 보였음. 그리고 간식 시간이었어서, 물과 간식을 사들고 다시 집으로 향함.

길 잘못 들러서 경부고속도로를 또 같은 방향으로 탔다. 그래서 동탄을 지나 오산까지 내려감. 오산 톨게이트를 빠져나온 후, 어디든 들어가서 유턴해서 되돌아갔다.

그렇게 경부선 타고 온 길로 그대로 돌아가면 됐는데, 또 다른 시도를 했다. 인천 방향으로 빠지는 것이다. 경부선 끝단으로 가면 신사역인지 어디인지, 여튼 강남권이다. 싫다. 막힐 것 같았다. 그래서 인천 방향으로 빠졌다. 서쪽으로 가다가 적당할 때 북진해서 집으로 가기로 했다. 무슨 도로인지도 모르고 그냥 쭉 따라왔다. 찾아보니 영동고속도로였음. 어디쯤에서 빠지지…? 하고 고뇌하던 찰나에, 서서울이 나옴. 개꿀! 나 서울 서쪽 삼! 바로 빠졌다.

익숙한 금천구가 나왔다. 고놈의 금천구! 얼마 안가 또 서부간선지하차도가 등장했다. 그거 뚫고 나오니, 다음 문제는 성산대교 vs 수서였다. 성산대교가 몇번째더라? 수서랑 수색도 맨날 헷깔려서 재확인이 필요했다. 하지만 곧 결론이 남. 수서엔 수서역이 있고, SRT에 좋은 노선 다 준다고 코레일이 삐졌던 사건을 알고 있다. 그럼 수서는 강남 근처일 것이다. 성산대교는 내가 일산에서 회사로 갈 때 중간에 지나친 대교다. 따라서 성산대교쪽이 확실히 서쪽이다. 성산대교쪽을 따라가서 건넜고, 강변북로에서 가양대교를 건너 집으로 돌아왔다.

후기: 기분 째질거같은데 에너지도 바닥 찢고 지하로 감.

반성: 적당히 하자.

OS - 2) Process API

이 단원은 실용적인 부분들, 즉 실제로 손맛 느껴보는 단원이다. 그래서 이론 위주의 공부를 하고싶은 사람은 넘겨도 된다고 써있었다. 하지만, 그거 아는가? 답정너식 화법 말이다. “난 이거 너희들이 읽었으면 좋겠지만, 이론 위주의 공부만 할거라면 넘겨도 돼. 근데 난 너가 이걸 읽었으면 좋겠어. 여튼 그렇다고. 아 네버 마인드.”

아아아아 알았다고! 그래서 여튼 읽었다. 이 공부, 급하지 않으니까. 손맛 한 번 느껴보자(하면서 실상 코드 손으로 안침 ㅋ).

이 단원은 fork, wait, exec 함수를 실제로 사용해보면서 무슨 일이 일어나는지를 이해하는 것을 목적으로 하고 있었다. 그래서 사용해보면서 또 GPT 선생 붙잡고 내가 이해한 내용이 맞는지 체크를 받으면서 추가적인 이해를 더했다.

fork()

프로세스를 복제떠서 자식 프로세스로 실행하는 함수이다. 처음엔 현재 상태의 메모리 자원을 공유한다. 그러다 수정이 일어나는 시점에 해당 자원을 카피해서 독립성을 부여한다.

Copy-on-Write(COW)라 칭한다.

그리고 좀 더 파봤는데, 커널 객체는 공유되고, 스택/힙/전역변수와 같은 유저공간 데이터는 복사가 일어난다. 커널 객체는 기본적으로 파일 디스크립터(fd)가 가리키는 객체인데, 파일, 소켓 버퍼, 파이프 버퍼 등이 있다. 사실 그냥 입출력 객체는 다 fd로 접근한다.

pipe는 ls | grep hello 할 때 그 pipe 맞다.

wait()

기다리는거 맞다. 누가 누굴 기다릴까? 부모가 자식을 기다린다.

exec()

다른 프로그램을 실행시켜서 프로세스를 전환하는 함수이다. 이 시점에서 프로세스는 전혀 다른 프로세스가 되어 있다. pid는 그대로다. 말 그대로 바꿔치기다.

왜 이걸 알아야 하는가

이게 미묘하다. 일반적인 케이스에서 이걸 다룰 일은 흔치 않다. 아니, 거의 없다고 봐도 무방하다. 하지만, OS관점에서 이 함수들은 아주 중요하다. OS가 하는 일 중 가장 중요한 일은 동시에 여러 프로세스를 돌리는 일이다. 그리고 OS도 하나의 프로그램이다. 즉, OS가 프로세스로서 다른 프로세스를 생성하고 관리하기 위해 fork, exec, wait은 필수불가결한 존재이다.

Process Control And Users

방금 본 저 3개의 함수 외에도, 프로세스를 컨트롤하는 함수들이 더 있다. 대표적으로 kill()이 있다. 말 그대로 kill이다. 근데, 죽인다고 생각하는게 아니라, 슬슬 꺼져랏! 하고 저주를 보내는 함수라고 보면 좋다. 프로세스로 시그널을 보내는 것이다. 익히 사용하는 Ctrl+C는 SIGINT, Ctrl+Z는 SIGSTOP이다. 둘 사이의 차이는, 쉽게 설명하면 “꺼져랏!”과 “비켜봐!”의 차이다. SIGINT는 정말 프로세스를 중단할 때 이용한다. 그에 반해, SIGSTOP은 잠시 멈춰주는 신호다. 실제로 프로세스의 state가 stop으로 변경된다. 그리고 그걸 다시 실행할 때는 fg 명령을 이용한다. 리눅스 사용하다가 간혹 Ctrl+Z를 잘못 누르면, 이렇게 살려내면 된다. 몰랐다면 참고 바람.

백그라운드 프로세스
SIGSTOP 후에 멈춘 프로세스는 백그라운드 프로세스가 아니다. 멈춰 있는 프로세스일 뿐이다. 이와 다르게, 백그라운드 프로세스는 돌고 있는 프로세스다. 단지 포그라운드가 아닐 뿐이다. 끝에 & 을 붙여서 실행한다던가 했을 때 생기는 프로세스가 백그라운드 프로세스다. SIGSTOP 후에는 bg 명령을 통해 백그라운드로 재개해야 백그라운드 프로세스로서 돌릴 수 있다.

프로그램에서 시그널을 받았을 때, 원하는 동작을 더 끼워넣으려면 signal() 함수를 이용해서 작정하면 된다.

그러면 한 가지 궁금증이 더해진다. 시그널은 어디로 들어올까? 부모? 자식? 알아보니, 해당 프로세스 그룹 전체에 도달한다. 부모와 자식 모두다.

다음은 유저로서 시그널을 어디까지 보낼 수 있는가에 대한 문제가 아직 남아있다. 기본적으로 시그널을 보낼 수 있는 대상은 같은 유저 소유의 프로세스에 한한다. 정리하면, 시그널은 같은 유저 소유의 프로세스 그룹에 보내진다.

그래서 이런 것도 가능하다. tty1에서 로그인한 후에 GUI를 올렸는데 그게 먹통이 되었다. 그럼 Ctrl+Alt+F#키를 이용해서 다른 tty로 진입하면 해결할 수 있다. 같은 유저로 로그인하거나, root로 로그인해서 그 GUI을 죽일 수 있다. 본체 버튼을 억지로 눌러서 비상종료할 필요가 없다.

RTFM: Read The Man Pages

동료에게 설명하기 귀찮을 때 RTFM을 시전하라고 한다. 이거 무슨 나같은 감성이다. 실제로 RTFM의 의미는 “Read The Fucking Manual”이라고 한다. 내 생각에 이건 그냥 “Read The Man Pages”로 풀어쓰는게 나을 듯 하다. 논쟁할 동료 학생이 없다. 회사에서 RTFM 그대로 쓰는 순간, 그냥 “책임지고 사퇴하겠습니다” 해야 한다. 만약 내가 RTFM을 외치면 퇴사 신호로 봐야 한다.

이후에 Useful Tools 챕터가 나왔는데, 리눅스 커맨드에서 자주 이용하는 기본 명령어들(ex. ps , top , kill)을 RTFM하라는 내용이라 굳이 남겨둘 만한 메모는 없다.

1종 수동 면허 취득

과한 운동은 아직이다. 가끔 에너지가 애매하게 차올라서 뇌가 착각을 하는지, “야야야 움직여! 뭐 해보자!!!!” 할 때가 있었다. 근데 그 때 그걸 따르면 초기화된다. 그걸 몇 번 당하고 나서, 적정 지점을 찾았는데, 그것은 드라이브였다. 운전을 하면 내 조작을 통해 실제로 속도가 발생한다. 그래서인지 뇌가 잘 속는 듯 하다. 그러고 나면 진정되고, 잠도 잘 온다. 효율이 좋다. 그 대신 허리 충격을 덜어주기 위해 충격흡수 방석을 깔고 운전하고, 복압을 유지하는데 신경을 쓴다.

드라이브는 어떻게 하냐면, 그냥 네비를 찍지 않고 아무 대나 찾아간다. 처음엔 집 근처에서 잠시 도는 정도였는데, 에너지 레벨이 회복되어 가면서 갈수록 길어졌다. 그래서 저번엔 자유로를 타고 쭉 가다가 판문점 표지판이 보여서 급히 빠져나와 임진각을 찍고 돌아왔다. 최근엔 인천공항을 찾아갔다. 그러나 나오는 길에 송도 표지판이 보이길래, 에너지가 남아서 학교를 찾아가서 찍고 돌아왔다.

송도는 근데 표지판 글씨가 너무 작아서 길을 많이 헤맸다. 글자가 보이면 이미 늦은 경우가 많았다. 정말 에너지 넘칠 때만 가야 한다.

그런 네비게이션 없는 드라이브를 하면서, 어느날 문득 운전 자체가 심심해졌다. 하지만 그렇다고 난폭운전을 할 수는 없다. 그 몇 초 사이의 고민 결과 “운전의 난이도를 올리면 되잖아?” 하는 묘안을 떠올렸다. 그래서 수동변속이 궁금해졌다. 그 길로 집 돌아가는 길에 운전면허학원에 들러서 1종 수동면허 과정을 등록하고 돌아왔다. 비용은 대충 50만원 정도 든다. 그걸 몇 초 사이의 고민 후에 질러버린 것이다. 이건 충동을 제어하지 못하는 비정상적인 정신상태에 기인한 지출이다. 따라서 의료비로 봐도 될듯? 물론 개소리다.

그래서 어찌저찌 수동변속기 사용법을 익히고 면허도 취득했다. 결과는 대만족이다. 자동변속기 차량을 운전하면서, 차를 멈추려고 브레이크를 잡고 있으면 마지막쯤에 뭔가 해방되듯 살짝 밀리는 현상을 느껴 왔는데, 그 이유를 알게 되었다. 1단 기어가 감당하는 속도 레벨 이하까지 내려가면 클러치를 밟아 동력을 해제하기 때문이다. 그러면 엔진브레이크에서 해방되고, 속도 감소폭이 줄어들게 되어 더 밀리는 듯한 느낌을 받는 것이다. 물론 이걸 알아낸 것도 좋았지만, 실제로 수동변속 자체가 재미있기도 했다. 아치리눅스 감성이다. 주석이 없어 추리해야 했던 그 체결률 공식의 중복된 두 파라미터의 관계같기도 했다. 물론 그건 필요없이 두 개가 된거지만, 이건 필요해서 2개다. 변속이 있으려면 파라미터가 두개여야 한다.

체결률 공식의 파라미터 이야기는, 대충 y절편을 변화시키는 파라미터가 2개 있었는데, 서로 그냥 곱하기였다. 하나는 분자에, 하나는 분모에 들어가는 느낌과 비슷하다.

물론, 막히는 길에서 지옥을 맛본다는 이야기에는 대찬성이다.

어른이 더 좋은 점

다들 어른이 되고 나서 힘들다 힘들다 하는데, 사실 그렇지만은 않다. 물론, 어른이 되면 자기를 스스로 책임져야 하기 때문에 누군가의 케어를 받던 시절보다 몇 배로 고달프고 힘든건 사실이다. 하지만, 그걸 하나씩 공략하는 맛도 있다. 초 고난이도 RPG 게임을 한다고 생각하자.

케어를 받는 대가

다들 자기가 케어를 받기만 했다고 생각한다. 하지만, 그 대가는 없지 않았다. 물론, 가족 뽑기운에 따라 이 대가의 크고 작음이 다르다. 누군가는 부모님이 강압적이어서 부모님 그늘 아래 꼭두각시처럼 살아야 하는 대가를 치른다. 누군가는 부모님의 인성이 나빠 스트레스를 지고 산다. 누군가는 부모님이 아프거나, 경제적 능력이 없어 소년/소녀가장을 해야 하는 경우도 있다(물론 이 경우 케어를 받는다고 하긴 어렵겠다). 또 누군가는 부모님의 전폭적인 지지 아래 꿈을 이루기 위해 드라이브를 걸기도 한다. 또 누군가는, 적당한 부모님 밑에서 평범하게 산다. 이건 다 뽑기운이다. 태어나는 것 자체도 내 선택이 아니기 때문이다. 그리고 내가 받은 유전자와 기질도 모두 뽑기운이다.

하지만 한 가지는 확실하다. 우린 대부분 학교에 다니면서, 얕디 얕은 다양한 과목을 공부한다. 연결고리를 하나씩 생략해 둔 채 암기를 요구한다. 내가 그 과목에 관심이 있든 없든, 어느 정도 강제적으로 그 공부를 해야 한다. 그럼 그게 잘못된 것일까? 아니다. 폭넓은 분야를 접하고 그에 대해 사고해보는 것은 인간으로서 기본 덕목을 기르는데 필수적이다. 말이 통하는 사회가 되기 위한 밑바탕이 된다. 물론 모두가 그걸 열심히 하지는 않지만, 적어도 그것들을 배울 기회를 제공하는 것은 필요하다.

그런 의미에서 수능과 대입에 도움이 안되는 과목들에 대해 아이들 학습로드만 가중시킨다고 주장하는 학부모들은 제일 먼저 자기 자신을 돌아봐야 한다고 생각한다. 아이들 학습 로드를 가중시키는 것은 학교가 아니라, 학원 뺑뺑이를 돌리는 부모들이다. 어차피 과목수 줄여도 애를 한시도 가만히 두지 않고 학원 뺑뺑이를 시키는건 매한가지일 것 아닌가. 문이과를 분리하고, 미적분을 없앤다 한들, 애들이 학원을 덜 다니고, 놀아야 할 때 더 놀았을까? 아니다.

또 한 가지, 그 시절은 점수가 전부인 것처럼 돌아간다. 아무리 다양한 경험을 했다고 해도, 그냥 점수로 요약된 후 대입에 소비하고 끝내버린다. 그리고 그 스토리들은 스스로 잡고 있지 않는 이상 휘발된다. 마치 한 사람의 인간으로서 지내지 않는 것과 비슷하다. 다행스럽게도 이 현상은, 연구/사무직군에 대한 투자 대비 매력도 하락으로 인해 꽤나 완화되고 있는 것으로 보인다. 각자 스탯이 많이 찍혀 있는 대로 직업을 가지고 적재적소에 배치되는 것이다. 하지만 이 변화의 중심에 있는 세대는 기성세대들과 한바탕 침튀기게 싸움을 해야 할 것이다. 자기 자신에 대해 있는 그대로를 받아들이라고 강요할 수 없는, 반대로 강요받을 수는 있는 그것이 바로 케어를 받는 대가이다.

어른이란

어른은 뭐 크게 대단한게 아니다. 내가 정의내린 어른의 기준은, 그냥 자기가 자기 입에 풀칠하는걸 스스로 하는가이다. 경제적인 이야기를 한거같지만, 그걸 시작으로 어른이 가지는 힘든 점과 좋은 점이 모두 따라온다. 구분하기 쉽도록 예시를 두 개 나열해보면 아래와 같다.

  1. 부모님과 함께 사는 사람은 어른일까? 만약 부모님과 함께 사는데, 그 가구에서 경제적으로 일조하고 있다면 어른이다. 하지만 그게 아니라 모든걸 빌붙으며 자기가 번 돈을 그저 모으고 있다면, 그건 어른이 아니다. 물론 여기서 반발할 사람이 많을 것이다. 자기 나름의 계산이 있을 것이고, 그것이 앞으로의 삶에 아주 유리한 방향은 맞기 때문이다.
  2. 부부 중 한 명이 전업주부를 한다면 그 사람은 어른이 아닐까? 아니다. 어른이다. 부부는 법적으로 경제공동체로 묶인 관계이기 때문에 그 공동체에 기여하는가가 중요하다. 전업주부는 가사노동을 통해 그 가정의 경제적 가치를 창출하고 있는 것이다. 그것이 없으면 외식, 돌봄 및 교육에 관한 비용이 추가로 들게 된다. 근데 만약 전업주부이면서 집안일을 하지 않는다면? 맞다. 그건 어른이 아니다. 만약 그 부부가 이혼했을 때, 한 쪽이 감정적인 부분 이외에 전혀 불편함을 느끼지 못한다면, 그건 한 쪽이 어린이었기 때문이라고 볼 수 있다.

주의할 것이 있다. 어른이 꼭 더 좋고 훌륭하고, 어린이는 그렇지 않은 존재라는 개념은 오류다. 모두 그냥 인격체다. 부모님과 함께 살며 자기 몫을 살뜰히 챙기는 사람은 결국 잘될 것이다. 감정이나 이상보다는 현실을 보는 사람이기 때문이다. 케어를 하는 주체가 객체를 그정도로 소중히 할 수 있다는 것은, 그 사람 자체가 그에게 그 정도의 가치가 있기 때문이다.

난 어른으로서 살기를 택했다. 그래서 위와 같은 기준에 따라, 일산의 부모님 소유 주택에서 지하에 방을 얻어 살 때, 매달 월세 명목으로 30만원을 부모님에게 송금했다. 증여세, 상속세 등의 세금 관점에서 봤을 때 어리석은 짓이긴 하지만, 이게 바로 적당한 집안 사람들이 누릴 수 있는 특권이기도 하다. 내 기준을 지키기 위해 일정 손해를 감수할 수 있는 것이 내 특권이다. 만약 우리 집안에 재산이 많았다면 이건 꿈도 못 꿀 것이다. 나라로부터 뚜드려맞을 세금폭탄이 두려워서라도 자기 기준을 져버리고 세금에 최적화된 재무적 관계를 유지해야 했을 것이다. 물론 그걸 모두 포기하는 방법도 있긴 하다. 마음먹기 더 어렵겠지만 말이다.

어른이 되면서 힘든 점

생각보다 스스로를 먹여 살리는게 힘들다. 어른은 곧 경제적 독립이라 했다. 그 독립은 일자리를 구하거나 사업을 해야 가능해지는데, 결국 사회의 톱니바퀴 중 하나가 된다는 뜻이다. 철광석을 갈고 갈아 결국 어디든 맞는 자리에 끼워넣는 것인데, 이게 쉬울 리가 없다. 수많은 충돌과 연마를 겪으며 자신의 자리를 찾아가게 되는데, 그 수준은 거의 생사를 오가는 수준이다. 부모와 학교의 보호를 받으며 자아관을 자유롭게 가질 수 있는 것은 어린이의 특권이다. 복권을 긁기 전에 그 복권의 결과는 자기 원하는 대로 상상해도 되는 것이다. 하지만 어른은 현실 속에 살아야 한다. 거기서 어린이는 한 번 이상 죽는다.

자기인식 자체에도 변화가 필요하다. 공학자와 기술자 중에서 뭘 할 것이냐 하고 이야기하며 은근하게 기술자를 까는 교수님의 이야기를 들으며 대학교를 다녀놓고, 난 기술자가 됐다. 마치 건축공학과에서 5년(설계 포함 과정)을 수료해 놓고, 자기가 설계자가 될 것으로 생각했던 사람이, 현장의 인부가 되는 것과 비슷하다. 깎아놓고 보니 그곳이 자기 자리였던 것이다.

의식주를 해결하는 것도 정말 어렵다. 하루 24시간 중 8시간을 업무에, 8시간을 수면에 할애하고 나면, 8시간이 남는데, 여기서 3시간은 요리하고 먹고 정리하는데 써야 하고, 2-3시간은 출퇴근에 사용해야 하고, 남은 2-3시간에 비로소 자기계발과 여가활동을 할 수 있다. 그리고 이조차도 야근 한 번에 날아가버리기 십상이다. 그래서 다른 뭔가를 줄인다. 잠을 줄이거나, 집안일을 미루거나, 끼니를 패스트푸드로 대체하거나, 거르거나. 그리고 그것이 건강을 서서히 망친다.

어른이 되면서 얻는 것

경제적 독립은 아주 많은 것들에서 자신을 해방시킨다. 대표적인 것이, 부모님이 내 삶에 대해 왈가왈부할 수 없게 된다. 내 앞가림만 제대로 하면, 터치를 잘 하지 않는다. 그래서 난 대학 졸업 후에 오히려 라크로스를 더 자유롭게 할 수 있었다. 과거 부모님은 내가 라크로스 때문에 고생했을 때 “니 앞가림에 더 신경써라” 라는 꾸중을 했지만, 지금은 반대로 라크로스에서 얻은 것들이 더 많음을 인정해 주신다. 심지어는 기부를 해도 그냥 “이제 그럴 때가 됐구나?” 해주신다.

기한없는 공부도 가능해진다. 학창시절의 시험이라는 제도는 공부의 기한을 정해버리고, 깊게 파는걸 방해한다. 깊게 파면 시간이 많이 들고, 시험 점수엔 도움이 되지 않는다. 근의 공식을 그냥 외우면 한 시간 정도에 몇 문제를 맞출 기반을 얻지만, 그 근의 공식을 직접 유도하고 있으면, 유도 후에 시험을 위해 외우는 시간이 따로 더해지거나, 실제 시험장 가서도 시간을 들여서 근의 공식을 유도해야 하는 대참사가 벌어진다. 그에 반해, 기한이 없는 공부는 근의 공식을 유도하면서 시간을 보내고 있어도 문제될 것이 없다. 그리고 그것이 공부의 맛이다. 새로운 것을 이해한 순간, “아하!”와 함께 쾌감을 느낄 것이다. 마치 머리 속에서 정리되지 않은 것들이 갑자기 정렬하면서 그 사이에 길이 직선으로 뚫리는 느낌이다.

또한, 만약 자신이 뽑기운이 좋지 않아 어릴 때부터 과한 짐을 지고 있었던 사람이라면, 자립을 계기로 그 짐을 벗어던질 수도 있다. 부모는 자식을 “태어나지게” 한 대가로 자식을 책임져야 한다. 자식의 탄생은 부모의 선택으로 인한 것이기 때문이다. 따라서 부모-자식 간의 관계를 정의하는덴 자식의 선택권이 더 크다. 자식이 적당할 때 부모의 품에서 벗어나는 것은 자연의 순리이기도 하기 때문에, 그것을 정의할 기회는 꼭 온다. 그리고 그 시점에 자식에게 선택권이 생긴다.

사회에서 갈리는 과정 또한 결과적으로 이득이다. 자신이 본래 가야 했던 자리를 알고 난 이후엔 묘한 안정감도 얻는다. 자기 자신을 모르는 상태에서 미래를 그리는 것은 엄청난 불안을 수반한다. 그 사람은 어른이 되어가는 과정에서 자기 자신의 장단점을 명확히 알아가게 된다. 직접 부딪혀 봤고, 실패할건 실패하고 성공할건 성공했으니 말이다. 자신의 장단점을 아는 상태에서 미래를 그리면 미래를 좀 더 명확하게 그릴 수 있다. 물론, 자기 자신을 안다고 해도, 세상을 잘 모르기 때문에 불안한 것은 매한가지다. 하지만 내가 통제할 수 있는 것과 없는 것이 무엇인지를 구분하고, 통제할 수 있는 것들에만 집중한다면, 적어도 졌잘싸는 할 수 있다. 그리고 그 통제할 수 있는 것들이 많아지는 방법은 바로 어른이 되는 것이다.

OS - 1) 프로세스

진지하게? 는 역시 어렵다. 사실 시도도 안했다. 회고록같은건 진지하게 써놓고 스터디는 안 진지하게 간다고? 그래야 스터디에 흥미를 안 잃기 때문이다. 회고같은 과거로 돌아가는 짓거리는 한 번이면 족하다. 그래서 진지하고 재미없게 써야 한다.

첫 단원은 프로세스다. OS에게 그 짓거리(가상화)를 시키게 한 주범이다. 프로그램을 실행하면 그게 프로세스다. 프로그램은 Disk에 잠들어 있는 프로세스의 전신이다. 대충 관짝에 잠들어 있는 미라를 생각하면 된다. 그걸 실행하면 프로세스로서 도는 것이다. 미라가 든 관짝을 툭툭 쳐서 주문을 읊는 것이다. 약속된 방법으로 읽어다가 프로그램을 메모리에 로드하고, CPU로 연산을 진행하면 프로세스다. 프로세스를 동시에 여러개 돌리고 싶으니, CPU를 시간분할하고, 메모리를 공간분할한다. 마찬가지 이유로, 컴퓨터가 프로그램을 하나만 가지고 있으면 나머지 공간이 아까우니, 공간분할을 통해 복수의 파일을 보관할 수 있게 한다.

분할

분할의 종류를 아주 간단하게 설명하면 아래와 같다.

  • 시간 분할(Time Sharing): 이거 하다가, 저거 하다가, 그거 하다가, …
  • 공간 분할(Space Sharing): 여기부터 여기까진 이거, 저기부터 저거까진 저거, …

프로세스는 시간분할의 예로 나와 있긴 한데, 그냥 뭐든 분할의 개념이 뒤섞여 있다. 프로세스들이 올라간 메모리의 각 위치는 공간 분할의 결과다. 프로세스들의 실제 연산은 시간분할을 통해 병렬인 것처럼 돌아간다.

디스크도 마찬가지다. 공간분할의 예로 나오지만, 디스크의 읽기/쓰기 동작은 시간분할이다. 얘도 어쨌든 하드웨어가 뭔 짓을 해야 일을 할 것 아닌가.

그래서 뭐는 뭐! 하는 사고방식은 오개념을 낳기 아주 쉽다고 본다.

시간 분할의 레벨

  • High-level(Policy): Scheduling - 이럴땐 이렇게… 지금이닷! Context Switching!
  • Low-level(Mechanism); Context Switching - 눼, 실행! @_@

그래서 프로세스가 뭔데?

책에서는 실행중인 프로그램에 대해 제공하는 추상화를 프로세스라 했다. 사실 프로세스가 뭐냐 물으면 실행중인 프로그램이라고 할텐데, 다음 설명을 위한 밑밥으로 저렇게 어려운 표현을 쓴 듯 하다. 근데, 이렇게 생각하면 재미가 없다. 추상화는 주판과 계산기를 생각하면 직관적으로 이해하기 쉽다. 사람이 주판 사용법을 익혀서 손으로 하나하나 튕구는건 불편하다. 그 과정은 따로 배워야 할 정도로 복잡하다. 그런데 그 과정을 묶어다가 버튼 기반 인터페이스를 올린다면? 물론 계산기 내부가 주판으로 되어 있는건 아니겠지만 말이다. 여튼 계산기는 a + b를 구하기 위해 손가락을 이래저래 튕길 필요 없이, a + b를 버튼으로 입력하기만 하면 된다. 계산하는 과정을 모아다가 사람이 쓰기 좋게 추상화한 결과인 것이다.

프로세스의 구성 요소

프로세스에서 접근할 수 있는 Machine State의 범위라고 보면 된다. Machine State는 CPU + 메모리 + I/O 장치 전체의 현재 상태를 뜻한다. 컴퓨터 켜는데 최소로 필요한게 CPU, 메모리, 디스크다. 그것들의 현재 상태라는 이야기다. 그냥 컴퓨터의 지금 상태다. 그리고 거기서 프로세스가 접근할 수 있는 범위는 아래와 같다.

  • 프로세스가 접근 가능한 메모리 영역(address space)

    • 프로그램을 메모리에 로드했을 때 그 구역이다.
    • 익히 들은 스택, 힙, 코드 영역 등이 그거다.
  • 레지스터(register)

    • 대충 CPU가 연산 중에 값을 잠시 보관해두는 곳이다. CPU에선 아래와 비슷하게 사용한다.
    MOV AX, 10 ; 10을 AX로 보내라
    MOV BX, 20 ; 20을 BX로 보내라
    ADD AX, BX ; BX를 AX에 더해라
    MOV BX, AX ; AX를 BX로 보내라
    ...
    
  • 영구저장장치(persistent storage device)

    • 디스크와 같이 영구저장을 위한 장치들이다. SSD, HDD, Flash 메모리가 대표적.
    • 근데, NVRAM은? → GPT선생이 가라사대, 그렇게 분류할 수는 있는데, OS 교재에서는 그거 취급 안한다 하였다.

Process API

아래는 OS에서 프로세스 관련 API로 제공해야 하는 것들이다.

  • Create
  • Destroy
  • Wait
  • Miscellaneous Control
  • Status

켜고(create) 끄는건(destroy) 당연히 있어야 하고, 부모가 자식 프로세스가 끝날 때까지 기다릴 수 있어야 하고(wait), 근데 이런저런 기능도 했으면 좋겠고(miscellaneous control), 프로세스의 현재 상태도 볼 수 있어야(status) 한다는 것이다.

Process Creation

잠든 미라를 깨워보자. 이 미라는 광부였다. 일단 디스크에서 파일이라는 관짝을 열어다가 미라를 갱도의 담당 구역으로 옮기는데(물론 실제로는 이동이 아니라 복사다), code와 static data을 메모리의 적절한 address space에 로드하는 것이다. 다음엔 담당 구역에 표시를 해준다. 스택과 힙 영역을 할당하는 것이다. 이후 미라를 깨워서 곡괭이를 손에 쥐어주고, “일해라” 하면, 그 미라는 일을 하게 될 것이다. CPU가 메인 함수를 시작으로 로직을 실제로 실행하는 것이다. 이 때, 메인함수여야 하는 이유는 간단하다. “일해라” 해야 일에 필요한 모든 것을 한다. “내려쳐라” 하면 그냥 그 자리에서 곡괭이를 아래로 내려치고 멈출 것이다. 다음은, 채광한 광물을 어딘가 저장하고 옮겨야 한다. 그래서 수레를 사용하면 이게 I/O 작업이다. 그 수레를 옮겨 광물을 창고로 넣으면 이건 영구저장장치에 저장한 무언가가 된다.

Process States

프로세스의 상태는 세 가지가 있다. 이거 state다. Status 아니다.

  • Running: 내 일 지금 진행되고 있음. 땡큐
  • Ready: 나 이제 준비됨. 시간 되면 내 일도 해줘.
  • Blocked: 아 뭐 기다리는 중임. 딴거 먼저 하세요. 아 건들지 말라고!

Running과 Ready 상태 사이의 전환은 스케줄러가 해준다. “피카츄, 너로 정했다! 가랏 백만볼트!” 해주는 것이다.

여기서, Blocked가 뭔지 궁금할 수 있다. 간단히 설명하면 정말 지금 다음껄 실행하면 안되는 상태다. 예를 들어, 파일의 내용을 읽는 작업이 있다고 치자. 그 작업을 디스크에 요청하면, 그 디스크가 그 작업을 끝내거나 중단할 때까지 프로세스의 다음 절차를 실행할 수 없다. 읽으라 해놓고 읽는걸 기다리지도 않고 “빨리 설명해봐!“ 하면 미친놈이다. 그래서 그걸 기다려달라고 표시하는 상태가 blocked다. Ready는 그냥 뒷전으로 밀려나 있는 일거리일 뿐, 언제든 실행될 수 있다.

하지만 실제로 예시로 제공된 xv6의 enum을 살펴보면, 다른 상태들도 몇 개 있다. 미사용(UNUSED), init 과정(EMBRYO), task가 다 돌고 난 이후(ZOMBIE)가 또 있다. 그리고 리눅스껀 또 다르다. 결국 이것도 구현하기 나름이라는 것이다.

UNUSED는 PCB(process control block)의 프로세스를 올릴 수 있는 슬롯이 미사용중이니 여기다 넣어도 된다는걸 나타내는 상태이다. 그래서 더 파보니, xv6같은 단순 OS는 미리 이 슬롯들을 정해진 크기로 할당해 둔 상태이기 때문에 있는 상태였다. 실제로 리눅스와 같이 실제로 이용하는 OS들은 동적으로 할당하는 방식이라 UNUSED 상태가 없다.

Data Structures

OS도 결국 다른 프로그램처럼 하나의 프로그램이기 때문에, 내부에 각종 데이터구조가 있다. 프로세스 구조체는 직접 그 소스를 보면 이해할 수 있다. 그중에서 가장 중요한 것은 context라 생각한다. 그리고 그 context 구조체를 보면, 그냥 레지스터의 값을 담는 구조체다. context switching이 발생하면, 직전에 running 상태였던 프로세스는 자신의 context에 레지스터를 저장하고, deregistered될 것이고, 이 프로세스는 context에 있던 레지스터의 값들을 레지스터로 다시 배치해서 EIP에 있는 코드를 실행할 듯 하다. 물론 context에 매 절차 마다 레지스터를 저장하는지, 컨택스트 스위칭이 일어날 때 저장하는지는 아직 모른다. 그건 OS를 개발하는 사람이 선택하면 될 일이기 때문에, 뚜렷한 답은 없을 것이고, 구현의 차이가 있을 듯 하다. 매번 저장하고 있으면 성능에 손해를 보기 때문에 아마 대부분 context switching이 일어날 때 저장하지 않을까 싶다. 물론 또다른 이유로 저장 주기를 타이트하게 가져갈 수도 있다. 장애를 대비한다던가? 우주방사선(????)을 대비한다던가?

다음으로, 프로세스의 실행 공간에 대한 정보가 있다. address space에 대한 것이다. 그 외에, 프로세스의 현재 상태에 관한 정보들이 포함되어 있다. process state 뿐만 아니라, 다른 더 필요한 것들도 있다. 쥐고 있는 파일들이라던가, 현재 디렉터리라던지 말이다.

OS - 0) Introduction

결국 여기까지 왔다. 네, Rust 커널 책 1-2주요? 개뿔! 초반에 Rust 언어의 사용법이 책 두께의 반 이상을 차지해서 얕봤다. 리눅스 커널 버전부터 다르고, Rust의 커널 관련한 부분의 개발이 활발한 바람에 이미 책은 EUC-KR 수준의 레거시가 되어 있었음. 실습 코드를 그냥 이해한 다음 그 목적을 하는 모듈을 짜보려다보니, 왜? 왜? 왜에에에에??? 가 연속되어 그냥 OS까지 들어가서 커널로 돌아오기로 했다.

정신 차리니 OS에 도착하는 과정
/dev/random 을 Rust로 구현하기 → 왜 딴 애들은 module! 매크로 이용해서 모듈 선언하는데, 얘는 module_misc_device! 지? → 그건 그렇고… 없네? → 대체제 찾았다! → file operations에서 read, write 정의 못하네? → c shim 가자 → 이 삽질 할 시간에 본진을 때리는게 낫지 않음?

최고의 방어는 공격이다. 그래서 ChatGPT에게 커리큘럼 내놓으라 함. 그래서 접한 책은 아래와 같다.

https://pages.cs.wisc.edu/~remzi/OSTEP/

pdf로 그냥 공개되어 있다.

여튼 그래서 슥 보고 있는데, 일단 개론 부분을 요약하면, OS가 존재하는 이유는 하드웨어 위에서 동시에 여러 일을 시키기 위해 가상화를 지원하는 것이다. cpu 1개짜리 머신이라고 프로그램 하나만 돌리면 아까우니까, 젖먹던 힘까지 다 끌어다 쓰기 위해 생긴거다. 힘내라 컴퓨터야. 인간들이 그렇지 뭐.

바이브코딩? 구그르(?)코딩?

누가 엑셀 매크로 짜는걸 도와달라 해서 visual basic을 처음으로 써보게 되었다. 그러면서 바이브코딩이 이게 맞는진 모르겠지만, 여튼 ChatGPT를 좀 많이 괴롭혔다.

일단 visual basic 소감은, 생각보다 왠만한 것들은 다 있고, 생각보다 이런 것도 없는 그런 묘한 언어이다. 게다가 매서드 실행 결과를 못믿겠음. 대표적인 예가 Find, FindNext였는데, 특정 문자열과 일치하는 셀을 찾기 위해 사용했지만, 그냥 빈 셀도 다 얻어걸려서 화딱지 나서 그냥 for문으로 순회를 돌렸다.

ChatGPT를 활용한 방법은 아래와 같다.

  1. function 정의 방법 → function, sub 차이점 이해
  2. sub을 한 모듈에서 여러개 선언해도 되는지, 함수 or 자료형 선언 순저 중요한지 → 언어 별로 다를 수 있는 부분들 미리 파악
  3. 엑셀 시트의 내용 파악(어디에 뭐가 있고 한지) → 목적을 달성하기 위해 로직을 주석으로 쭉쭉 씀
  4. 주석을 구현하기 위해 “이런거 됨?” 하고 ChatGPT에 질문 → 잘 알려줌
  5. 데이터 파싱 되는 것 확인 후 시트에 쓰기 로직 구현
  6. 디버깅 및 삽질

잘 보면 그냥 구글 대신 ChatGPT를 쓰는 것과 같다.

나도 늙었나보다. 난 구글 세대입니다…

한가지 많이 불편했던 것은, 엑셀이 설치되어 있는 윈도우에서 작업하려니, vim 못씀. 그래서 코파일럿도 못썼다. 이 케이스에선 코파일럿이 더 편했을 듯 하다. 코파일럿 썼으면 바이브코딩이라고 봐도 될 듯?

타협 vs 고집

Rust 커널 서적에서 사용하는 함수들이 죄다 옛날 커널 기준이다. 지금 난 6.16 버전 받아다가 하고 있으니, 당연히 한 스텝 마다 막힘.

이쯤에서 선택지는 2개가 있다

  1. 옛날 커널을 받아서 쓴다
  2. 싸운다

일단 2번으로 하고 있다. 1주일에 커널 서적 끝내긴 개뿔. 회사 복귀 후에도 계속 싸워야 할 듯 하다.

그래도 2번을 고집하는 이유는, 1번보다 많은 것을 얻을 수 있기 때문이다. 마치 아무 대책 없이 노트북 OS 날려버리고 아치리눅스를 설치한 것과 비슷하다. 적응을 강제하는 환경을 만들어버렸더니, 아치리눅스 사용법 뿐만 아니라 개발 중에 만사에 당황하지 않는 멘탈도 얻었다.

처음에 싸우던 방법은 진짜 그 코드를 그대로 두고 조금씩 바꿔쓰기 위해 ChatGPT에 “이거 대체할 수 있는 함수나 매크로 뭐임?” 하고 물어봤다. “아 그 낡은거 왜 궁금해함? 이거같은데?” 하고 잘 답해주긴 한다. 하지만 그 대답이 쓸데없이 길다. 대부분 “그거 여기어디 있는데, export 안됨. ㅋ. 직접 c로 shim 짜셈” 이다. 걔가 코드 쭉 써준걸 보면, 그냥 rust로 쓴 척 하는 c 모듈 코드다. 그리고 잘 돌지도 않음. 물론 내 손이 문제겠지만 말이다.

그래서 바꾼 방법은, 코드 슥 읽은 다음에 그 목적을 달성하는 모듈을 직접 짜는 방법이다. 이렇게 하려니 직접 커널 소스를 돌아다니면서 찾아야 한다. 근데 아직 코드베이스 자체가 익숙치 않으니 감이 잘 안잡힘. 그 부분부터 잡아야 할 듯 하다. C 기반으로 된 책도 있긴 한데, 무슨 Calculus마냥 두꺼워서 아직 엄두는 안남. 일단 싸우고 나서 생각해 볼 예정이다.

Rust 커널

커널 버전 6.1에 rust 지원되는거 기대할 필요는 무슨. 6.16이 넘어가도록 건드리지도 못했다. 책 신나게 사놓고 말이다. 병가 4주차를 맞이하여, 이제 회사 시간표에 준하는 활동을 하고 있다. 따라서 본격적으로 진도를 나가고 있다. 오늘 4주차 일정 처음인데… 좀 딸리긴 한다. 그래서 3번째 활동 블록(대충 2-3시간 텀 주고 휴식 넣어서 잘랐음)땐 허리보호대를 착용하고 있었다. 아 그리고 뜬금없이 귤이 생각나서 점심 때 사와서 오후 간식 시간에 먹었는데, 정신이 돌아옴. 비타민 부족인가보다. 왜? 그래도 영양소 더듬이(?)는 감도가 좋아진 것 같아서 나름 만족이다. 단어 안 떠올라서 지맘대로 쓰는건 지금도 마찬가지다.

공부는 그냥 책 따라가고 있다. Rust-for-Linux의 소스를 가져다가 커널을 빌드하고, 만들어낸 모듈도 그 소스를 이용해서 빌드. 테스트는 qemu vm 위에서 테스트해보는 식으로 실습을 진행하고 있다. 실습 git repo는 아래와 같다.

https://github.com/Xanthorrhizol/rust-kernel-study

문제는 2가지였다.

제일 먼저, vim에 연동된 rust-analyzer에서 지원하게 하고 싶었다. vim을 주 도구로 사용하긴 하지만 메모장 코딩은 나도 싫다. 그래서 또 vim 세팅이랑 싸웠다. 프로젝트 최상단에 rust-project.json 생성한 후 ~/.vim/coc-settings.json 에다가 rust language server에서 rootPatternsrust-project.json 도 지원하게 추가하면 되는거였는데, 또 여기서 난리를 침.

다음은 책 내용의 예제가 버전이 안맞아서 deprecated된 모듈들과 한바탕 싸움질을 해야 했다는 것이다. 첫 예제인 printk부터 말이다. 다음 예제는 module 매크로 내부의 params 파라미터를 사용해보는 것인데, 이것도 deprecated다. printk는 그래도 옵션 켜면 vprintk라는 대체 함수가 제공되었는데, params는 대체함수도 없고, ffi로 직접 구현해야 한다. 그 삽질을 하다가 printk만 커밋했음.

강하게 키우는가보다. 덤벼라.