Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม C

เข้าใจ System Calls: วัตถุประสงค์ การทำงาน และการใช้งานทั่วไปใน Linux

เข้าใจ System Calls: วัตถุประสงค์ การทำงาน และการใช้งานทั่วไปใน Linux

บทนำ

ในบทความนี้ เราจะอธิบายว่า System Calls (SysCalls) คืออะไร ใช้ทำอะไร และแตกต่างจากฟังก์ชันในไลบรารีมาตรฐาน C อย่างไร เราจะแสดงบทบาทของพวกมันต่อเคอร์เนลในระบบ และกระบวนการใช้บริการที่พวกมันให้มา พร้อมรายการ System Calls ที่ใช้บ่อยที่สุด พร้อมคำอธิบายสั้นๆ และไฟล์หัวข้อที่ประกาศ รวมถึงวิธีติดตามการทำงานของ System Calls ผ่านคอนโซลคำสั่ง

แนวคิดชั้นของระบบ (System Layers)

ทุกระบบประกอบด้วยชั้นต่างๆ ที่แต่ละชั้นมีหน้าที่และสิทธิพิเศษของตัวเอง เริ่มจากระดับต่ำสุดคือ ฮาร์ดแวร์ และสิ้นสุดที่ชั้นบนสุดที่เรียกว่า User Mode

โปรแกรมทั้งหมดที่เรารันบนคอมพิวเตอร์ และโค้ดทั้งหมดที่เราเขียนและคอมไพล์ จะทำงานเป็นกระบวนการใน User Mode ของระบบ ในโหมดนี้ ผู้ใช้ทำงาน ใช้แอปพลิเคชัน จัดการไฟล์ ฯลฯ ด้านความปลอดภัย นี่คือชั้นที่ตื้นที่สุดของระบบ จึงถูกจำกัดมากที่สุด และโดยค่าเริ่มต้นถูกจำกัดให้ไม่สามารถจัดการทรัพยากรระบบโดยตรงได้

ชั้นฮาร์ดแวร์เป็นระดับต่ำสุด ขึ้นไปด้านบนคือ Linux Kernel เคอร์เนลคือหัวใจของระบบปฏิบัติการ ที่ผสานรวมกับฮาร์ดแวร์และจัดการอย่างเคร่งครัด เป็นผู้เดียวที่มีสิทธิ์ทำได้ ตัวอย่างเช่น การจัดการกระบวนการและหน่วยความจำ การเข้าถึงข้อมูลจากฮาร์ดดิสก์หรือ SSD การควบคุมอุปกรณ์เครือข่าย ทุกอย่างที่ OS และกระบวนการทำกับฮาร์ดแวร์ ผ่านเคอร์เนลเสมอ

เนื่องจากข้อจำกัดในการเข้าถึงและจัดการทรัพยากรที่ OS กำหนดให้กับ User Mode และการเข้าถึงทรัพยากรนี้เป็นไปได้เฉพาะผ่านเคอร์เนล จึงจำเป็นต้องมีกลไกที่ช่วยให้กระบวนการโต้ตอบกับทรัพยากรที่ต้องการเพื่อทำงานได้

System Calls คืออะไร?

System Calls (SysCalls) เป็นชุดฟังก์ชันที่ระบบปฏิบัติการจัดเตรียไว้ ทำหน้าที่เป็น อินเทอร์เฟซระหว่างกระบวนการผู้ใช้ (user process) และเคอร์เนล (kernel) ฟังก์ชันเหล่านี้ช่วยให้เราโต้ตอบกับ OS และร้องขอบริการที่ต้องใช้ทรัพยากรระบบผ่านเคอร์เนล SysCalls ไม่ได้ให้สิทธิ์เข้าถึงทรัพยากรโดยตรง แต่เคอร์เนลเป็นผู้จัดการและทำให้ทรัพยากรพร้อมใช้งานให้กระบวนการที่เรียก ภายใต้การจัดการที่เคร่งครัดของเคอร์เนล

ในทางปฏิบัติ ฟังก์ชัน System Call ดูเหมือนฟังก์ชันทั่วไป และถูก implement แบบนั้น มีอาร์กิวเมนต์นำเข้าสำหรับส่งข้อมูลที่จะประมวลผล และอาร์กิวเมนต์ส่งออกสำหรับรับผลลัพธ์จาก OS วิธีการเรียกใช้เหมือนฟังก์ชันทั่วไปในไลบรารี C ดังนั้นคำถามว่าเป็นฟังก์ชันเรียกหรือไม่ ในทางปฏิบัติเป็นคำถามเชิงแนวคิดเพียงอย่างเดียวสำหรับนักเขียนโปรแกรม

อาร์กิวเมนต์ของฟังก์ชันเหล่านี้ใช้ชนิดข้อมูลมาตรฐานของภาษา C แม้ว่าจะมักเป็นพอยน์เตอร์ที่เก็บที่อยู่หน่วยความจำ descriptors paths ฯลฯ ตามลักษณะงานของมัน

ใน Linux ปัจจุบันมี System Calls ประมาณ 350 ตัว นอกจากนี้ยังมีฟังก์ชันจำนวนมากที่ไม่ใช่ System Calls แต่จัดการทรัพยากรผ่าน SysCalls เช่น malloc() free() calloc() realloc() ที่จัดการหน่วยความจำแบบไดนามิกโดยใช้ syscalls ในโค้ดของพวกมัน

การติดตาม System Calls ด้วยคำสั่ง strace

คำสั่ง strace ใช้ติดตาม system calls แบบ real-time จากคอนโซล Linux ค่อนข้างยืดหยุ่น มีตัวเลือกมากมาย ดูได้ด้วยคำสั่ง:

strace -h

เข้าใจ System Calls: วัตถุประสงค์ การทำงาน และการใช้งานทั่วไปใน Linux

เพื่อติดตาม syscalls ของกระบวนการ ให้รันด้วย:

strace ./process

ตัวอย่างการติดตามจริง

เราใช้โค้ดตัวอย่างจากบทความ "Connect Function in C language" ซึ่งเชื่อมต่อกับ Google ผ่าน HTTP ส่งคำสั่งและรับการตอบสนอง

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

int main() {
    // ... โค้ดการเชื่อมต่อ socket ...
}

คอมไพล์แล้วรันด้วย strace:

strace ./connect

เข้าใจ System Calls: วัตถุประสงค์ การทำงาน และการใช้งานทั่วไปใน Linux

จากภาพ แม้โค้ดเราจะใช้แค่ socket() connect() send() recv() แต่การรันจริงต้องการ system calls อื่นๆ มากมายที่เกิดจากโค้ดภายในฟังก์ชันที่เราใช้

คำสั่งแสดงสรุป system calls เมื่อกระบวนการสิ้นสุด:

strace -c ./connect

เข้าใจ System Calls: วัตถุประสงค์ การทำงาน และการใช้งานทั่วไปใน Linux

รายการ System Calls ที่ใช้บ่อย

System Calls สำหรับจัดการกระบวนการ

FunctionDescriptionHeader
execl(), execlp(), execle(), execv(), execvp(), execvpe()กลุ่มฟังก์ชันแทนที่กระบวนการหนึ่งด้วยอีกตัวหนึ่ง โดยสืบทอด PID และทรัพยากรจากกระบวนการแม่unistd.h
fork()สร้างกระบวนการลูกโดยโคลนกระบวนการแม่unistd.h
getpid()ดึง PID ของกระบวนการที่เรียกunistd.h
getppid()ดึง PID ของกระบวนการแม่unistd.h
exit()แจ้งสถานะการออกจากกระบวนการstdlib.h
getcwd(), getwd()คืนสตริงไดเรกทอรีทำงานปัจจุบันunistd.h
pause()หยุดกระบวนการจนกว่าจะได้รับสัญญาณunistd.h
wait()รอผลลัพธ์จากกระบวนการลูกwait.h

System Calls สำหรับจัดการไฟล์

FunctionDescriptionHeader
open(), openat()เปิดไฟล์fcntl.h
close()ปิดไฟล์unistd.h
read()อ่านไฟล์unistd.h
poll()ตรวจสอบความพร้อมของไฟล์สำหรับการดำเนินการเฉพาะpoll.h
write()เขียนไฟล์unistd.h
fcntl()จัดการ file descriptorsfcntl.h
truncate(), ftruncate()ตัดไฟล์ให้มีความยาวตามที่กำหนดunistd.h
creat()สร้างไฟล์fcntl.h
chmod(), fchmod()ตั้งค่าสิทธิ์ไฟล์sys/stat.h
unlink()ลบไฟล์unistd.h

System Calls สำหรับจัดการสัญญาณ (Signals)

FunctionDescriptionHeader
signal()เชื่อมโยงสัญญาณกับ handlersignal.h
kill()ส่งสัญญาณไปยังกระบวนการsignal.h
killpg()ส่งสัญญาณไปยังกลุ่มกระบวนการsignal.h
raise()ดำเนินการของสัญญาณในกระบวนการที่เรียกsignal.h
sigaction()ตั้งค่าการกระทำของสัญญาณsignal.h
sigwait()ระงับการทำงานจนกว่าจะได้รับสัญญาณที่ระบุsignal.h
sighold()เพิ่มสัญญาณเข้า signal masksignal.h
sigignore()เพิกเฉยสัญญาณsignal.h
sigblock()บล็อกสัญญาณsignal.h
psignal(), psiginfo()พิมพ์ข้อความอธิบายสัญญาณsignal.h

System Calls สำหรับจัดการ Socket

FunctionDescriptionHeader
socket()สร้าง socketsocket.h
bind()ผูกชื่อกับ socketsocket.h
connect()เชื่อมต่อ socketsocket.h
listen()ฟังการเชื่อมต่อบน socketsocket.h
accept()ยอมรับการเชื่อมต่อบน socketsocket.h
recv(), recvfrom(), recvmsg()รับข้อความจาก socketsocket.h
send(), sendto(), sendmsg()ส่งข้อความผ่าน socketsocket.h
getsockname()คืนที่อยู่ของ socket จาก descriptorsocket.h
getsockopt()ตั้งค่าหรือดึงค่าตัวเลือก socketsocket.h

สรุป

บทความนี้ได้อธิบายว่าฟังก์ชัน System Call คืออะไร และใช้ร้องขอบริการเคอร์เนลที่เกี่ยวข้องกับทรัพยากรระบบอย่างไร แสดงการโต้ตอบระหว่างกระบวนการผู้ใช้และเคอร์เนลผ่าน System Calls พร้อมรายการ System Calls ที่ใช้บ่อยที่สุด คำอธิบายสั้นๆ และไฟล์หัวข้อที่ต้อง include รวมถึงวิธีติดตาม syscalls ของกระบวนการผ่านคอนโซลคำสั่ง