Tải bản đầy đủ (.pdf) (33 trang)

slide bài giảng tổng quan về linux chương 12 linux programing

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (5.51 MB, 33 trang )

Linux ProgramingLinux Programing
System callsSystem calls
 System call thường là một yêu cầu đến hệ điều System call thường là một yêu cầu đến hệ điều
hành để làm một tác vụ phần cứng/chuyên biệt hành để làm một tác vụ phần cứng/chuyên biệt
hệ thống hay tác vụ đặc quyền hệ thống . hệ thống hay tác vụ đặc quyền hệ thống .
 Trong LinuxTrong Linux 1.2 có 140 system calls được định 1.2 có 140 system calls được định
nghĩa. nghĩa.
 System calls như System calls như close()close() được hiện thực trong được hiện thực trong
Linux libc. Linux libc.
 Việc hiện thực này xoay quanh việc gọi một là Việc hiện thực này xoay quanh việc gọi một là
syscall().syscall().
 Các tham số truyền vào syscall() là số hiệu Các tham số truyền vào syscall() là số hiệu
system call và được theo sau bởi các tham số system call và được theo sau bởi các tham số
cần thiết cần thiết
System callsSystem calls
 Số hiệu của system call có tìm thể thấy ở Số hiệu của system call có tìm thể thấy ở
 < linux/unistd.h > < linux/unistd.h >
 Trong đó < sys/syscall.h > được cập nhật Trong đó < sys/syscall.h > được cập nhật
với libc mới.với libc mới.
 Nếu có các calls xuất hiện mà chúng chưa Nếu có các calls xuất hiện mà chúng chưa
có trong libc, ta có thể gọi syscall().có trong libc, ta có thể gọi syscall().
System callsSystem calls
 Ví dụ, ta có thể đóng file dùng syscall() như sau Ví dụ, ta có thể đóng file dùng syscall() như sau
(không khuyến khích):(không khuyến khích):
 #include <syscall.h>#include <syscall.h>
 extern int syscall(int, );extern int syscall(int, );
 int my_close(int filedescriptor)int my_close(int filedescriptor)
 {{
 return syscall(SYS_close, filedescriptor);return syscall(SYS_close, filedescriptor);
 }}
System call ParametersSystem call Parameters


 Trên kiến trúc i386 , system calls bị giới hạn đến Trên kiến trúc i386 , system calls bị giới hạn đến
5 tham số không kể đến số hiệu system call bởi 5 tham số không kể đến số hiệu system call bởi
vì việc hạn chế số lượng thanh ghi vì việc hạn chế số lượng thanh ghi
 Nếu bạn dùng Linux trên một kiến trúc khác, ta Nếu bạn dùng Linux trên một kiến trúc khác, ta
có thể check kiểm tra <asm/unistd.h> để tìm có thể check kiểm tra <asm/unistd.h> để tìm
các syscall macros để xem phần cứng của bạn các syscall macros để xem phần cứng của bạn
có thể hỗ trợ đến bao nhiêu tham sốcó thể hỗ trợ đến bao nhiêu tham số
 Các syscall macro này có thể được dùng thay Các syscall macro này có thể được dùng thay
thế cho syscall(), nhưng nó không được khuyến thế cho syscall(), nhưng nó không được khuyến
khích khi đã có những macro được phát triển khích khi đã có những macro được phát triển
thành các hàm đầy đủ tồn tại trong thư viện lập thành các hàm đầy đủ tồn tại trong thư viện lập
trìnhtrình
System call Parameters (tt)System call Parameters (tt)
 Do đó chỉ có những tay chuyên nghiệp mới nên Do đó chỉ có những tay chuyên nghiệp mới nên
chơi với các syscall macros. Ví dụ đây là một chơi với các syscall macros. Ví dụ đây là một
hàm close() có dùng syscall macro.hàm close() có dùng syscall macro.
#include <linux/unistd.h>#include <linux/unistd.h>
_syscall1(int, close, int, _syscall1(int, close, int,
filedescriptor);filedescriptor);
 syscall1 macro mở rộng hàm close(). Do đó ta syscall1 macro mở rộng hàm close(). Do đó ta
có close() xuất hiện 2 lần: một trong libc và một có close() xuất hiện 2 lần: một trong libc và một
trong chương trình của ta. Giá trị trả về của trong chương trình của ta. Giá trị trả về của
syscall() hay syscall macro là syscall() hay syscall macro là 1 nếu system call 1 nếu system call
thất bại và 0 hoặc lớn hơn nếu thành công. thất bại và 0 hoặc lớn hơn nếu thành công.
System Call không có trong LinuxSystem Call không có trong Linux
 Các system call sau là tồn tại trên BSD và Các system call sau là tồn tại trên BSD và
SYS V nhưng không tồn tại trên Linux:SYS V nhưng không tồn tại trên Linux:
 audit(), auditon(), auditsvc(), fchroot(), audit(), auditon(), auditsvc(), fchroot(),
getauid(), getdents(), getmsg(), mincore(), getauid(), getdents(), getmsg(), mincore(),
poll(),putmsg(), setaudit(), setauid(). poll(),putmsg(), setaudit(), setauid().

The “swiss army knife” ioctlThe “swiss army knife” ioctl
 phillips screwdriver, screwdriver,
screwdriver, screwdriver, corkscrew,
scissors, metal saw, wood saw, can
opener, mini screwdriver, nailfile,
metal file, wire bender, large blade,
small blade, cap lifter, wire stripper,
reamer, punch, key ring, tweezers,
multi-purpose hook, chisel, wire cutters, pin, nail cleaner,
multipurpose pliers, clef 6 pans 5mm pour connecteurs D-
SUB,embout Pozidrive 0, embout Pozidrive 1, embout
tournevis, embout Phillips 2, embout Hex (inbus), embout
Torx 8, embout Torx 10, embout Torx 15, long ballpoint
pen, toothpick
/>The “swiss army knife” ioctlThe “swiss army knife” ioctl
 ioctl viết tắt cho input/output control và ioctl viết tắt cho input/output control và
nó được dùng để thao tác đến các nó được dùng để thao tác đến các
character device thông qua filedescriptor. character device thông qua filedescriptor.
 Format của ioctl là Format của ioctl là

ioctl(unsigned int fd, unsigned int request, ioctl(unsigned int fd, unsigned int request,
unsigned long argument)unsigned long argument)
. .
 Giá trị trả về là Giá trị trả về là 1 nếu có lỗi và =0 nếu 1 nếu có lỗi và =0 nếu
request thành công (tương tự như các system request thành công (tương tự như các system
call khác). call khác).
ioctl (tt)ioctl (tt)
 Kernel phân biệt các file đặc biệt và file thông Kernel phân biệt các file đặc biệt và file thông
thường . File đặc biệt là những file nằm trong thường . File đặc biệt là những file nằm trong
/dev và /proc. Chúng khác với các file thông /dev và /proc. Chúng khác với các file thông

thường là chúng dấu các giao diện với driver thường là chúng dấu các giao diện với driver
và không phải là một file thật sự chứa dữ liệu và không phải là một file thật sự chứa dữ liệu
text hay binary. Đây là triết lý của UNIX và text hay binary. Đây là triết lý của UNIX và
cho phép dùng các thao tác read/write thông cho phép dùng các thao tác read/write thông
thường trên tất cả các file. thường trên tất cả các file.
 Bạn sẽ cần dùng ioctl nhiều khi thao tác với Bạn sẽ cần dùng ioctl nhiều khi thao tác với
các file đặc biệt hơn là với các file thường. các file đặc biệt hơn là với các file thường.
Nhưng bạn cũng có thể dùng ioctl trên các file Nhưng bạn cũng có thể dùng ioctl trên các file
thường !thường !
IInternterPProcess rocess CCommunicationsommunications IPC IPC
 Cơ chế IPC trong Linux cung cấp một phương
pháp cho nhiều tiến trình giao tiếp với nhau. Có
nhiều phương pháp IPC cho Linux C
programmers áp dụng:
 Half-duplex UNIX pipes
 FIFOs (named pipes)
 SYSV style message queues
 SYSV style semaphore sets
 SYSV style shared memory segments
 Networking sockets (Berkeley style, không đề cập )
 Full-duplex pipes (STREAMS pipes,, không đề cập )
 Các phương pháp này, khi được dùng một cách
hiệu quả, sẽ mang lại một framework vững chắc
cho client/server development trên bất kỳ một
hệ UNIX nào (bao gồm cả Linux).
HalfHalf duplex UNIX Pipesduplex UNIX Pipes
 Khái niKhái niệm căn bản: ệm căn bản:
pipe pipe
là một phương là một phương
pháppháp của việc kết nối của việc kết nối

standard output standard output
của một của một
tiến trình process vào một tiến trình process vào một
standard input standard input
của của
tiến trình khác. Pipes là một công cụ IPC cổ tiến trình khác. Pipes là một công cụ IPC cổ
nhất, nó có từ giai đoạn phôi thai nhất của HĐH nhất, nó có từ giai đoạn phôi thai nhất của HĐH
UNIX. Chúng cung cấp một của việc giao tiêế 1 UNIX. Chúng cung cấp một của việc giao tiêế 1
chiều (thuật ngữ halfchiều (thuật ngữ half duplex) giữa các process. duplex) giữa các process.
Tính năng này được dùng rộng rãi, thậm chí Tính năng này được dùng rộng rãi, thậm chí
trong shell của Unixtrong shell của Unix
ls | sort | lp
HalfHalf duplex UNIX Pipesduplex UNIX Pipes
 Tạo pipes trong CTạo pipes trong C
 Để tạo một pipe đơn giản trong C, ta cần Để tạo một pipe đơn giản trong C, ta cần
dùng pipe() system call. Nó cần 1 tham số, đó dùng pipe() system call. Nó cần 1 tham số, đó
là một array có 2 số integer và nếu thành là một array có 2 số integer và nếu thành
công, array sẽ chứa 2 file descriptors mới để công, array sẽ chứa 2 file descriptors mới để
được dùng cho pipeline. Sau khi tạo pipe, được dùng cho pipeline. Sau khi tạo pipe,
process thường sinh ra 1 tiến trình mới (lưu ý process thường sinh ra 1 tiến trình mới (lưu ý
rằng, tiến trình con thừa kế mô tả file đã mở).rằng, tiến trình con thừa kế mô tả file đã mở).
TTạo ạo pipes trong Cpipes trong C
 SYSTEM CALL: pipe();SYSTEM CALL: pipe();
 PROTOTYPE: int pipe( int fd[2] );PROTOTYPE: int pipe( int fd[2] );
 RETURNS: 0 on successRETURNS: 0 on success
 1 on error: errno = EMFILE (no free 1 on error: errno = EMFILE (no free
descriptors)descriptors)
 EMFILE (system file table is full)EMFILE (system file table is full)
 EFAULT (fd array is not valid)EFAULT (fd array is not valid)
 NOTES: fd[0] is set up for reading, fd[1] is set NOTES: fd[0] is set up for reading, fd[1] is set

up for writingup for writing
TTạo ạo pipes trong Cpipes trong C
 Giá trị integer đầu tiên trong array được thiết Giá trị integer đầu tiên trong array được thiết
lập và mở ra cho việc đọc, trong khi số integer lập và mở ra cho việc đọc, trong khi số integer
thứ hai được thiết lập và mở ra cho việc ghi. thứ hai được thiết lập và mở ra cho việc ghi.
 Nói một cách hình tượng, output của fd1 trở Nói một cách hình tượng, output của fd1 trở
thành input cho fd0. Một lần nữa, tất cả data di thành input cho fd0. Một lần nữa, tất cả data di
chuyển thông qua pipe đi vào kernel.chuyển thông qua pipe đi vào kernel.
#include <stdio.h>#include <stdio.h>
#include <unistd.h>#include <unistd.h>
#include <sys/types.h>#include <sys/types.h>
main()main()
{{
int fd[2];int fd[2];
pipe(fd);pipe(fd);
……
}}
Ví dụVí dụ
/***MODULE: pipe.c***//***MODULE: pipe.c***/
#include <stdio.h>#include <stdio.h>
#include <unistd.h>#include <unistd.h>
#include <sys/types.h>#include <sys/types.h>
int main(void)int main(void)
{{
int fd[2], nbytes;int fd[2], nbytes;
pid_t childpid;pid_t childpid;
char string[] = "Hello, world!char string[] = "Hello, world!\\n";n";
char readbuffer[80];char readbuffer[80];
pipe(fd);pipe(fd);
if((childpid = fork()) == if((childpid = fork()) == 1){1){

perror("fork");perror("fork");
exit(1);exit(1);
}}
if(childpid == 0) {if(childpid == 0) {
/* Child process closes up input side /* Child process closes up input side
of pipe */of pipe */
close(fd[0]);close(fd[0]);
/* Send "string" through the output /* Send "string" through the output
side of pipe */side of pipe */
write(fd[1], string, strlen(string));write(fd[1], string, strlen(string));
exit(0);exit(0);
}}
else {else {
/* Parent process closes up output /* Parent process closes up output
side of pipe */side of pipe */
close(fd[1]);close(fd[1]);
/* Read in a string from the pipe *//* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, nbytes = read(fd[0], readbuffer,
sizeof(readbuffer));sizeof(readbuffer));
printf("Received string: %s", printf("Received string: %s",
readbuffer); }readbuffer); }
return(0);return(0);
}}
Các lưu ý trong
half-duplex pipes
 pipes hai chiều có thể được tạo ra bằng cách mở pipes hai chiều có thể được tạo ra bằng cách mở
hai pipes, và được gán lại file descriptors một hai pipes, và được gán lại file descriptors một
cách thích hợp trong tiến trình con .cách thích hợp trong tiến trình con .
 Lời gọi pipe() phải được thực hiện trước khi gọi Lời gọi pipe() phải được thực hiện trước khi gọi
fork(), nếu không thì descriptors sẽ không được fork(), nếu không thì descriptors sẽ không được

thừa kế bởi tiến trình con ! thừa kế bởi tiến trình con !
 Với halfVới half duplex pipes, bất kỳ tiến trình kết nối duplex pipes, bất kỳ tiến trình kết nối
nào phải được chia sẽ cùng một tổ tiên. Khi pipe nào phải được chia sẽ cùng một tổ tiên. Khi pipe
cư trú bên trong sự kềm hãm của kernel, bất cứ cư trú bên trong sự kềm hãm của kernel, bất cứ
một tiến trình nào mà không cùng tổ tiên của một tiến trình nào mà không cùng tổ tiên của
pipe thì không có cách nào tìm đến được nó. pipe thì không có cách nào tìm đến được nó.
Named Pipes (FIFOs)Named Pipes (FIFOs)
 Khái niệm: named pipe hoạt động giống Khái niệm: named pipe hoạt động giống
như pipe thông thường, nhưng có một số như pipe thông thường, nhưng có một số
khác biệt đáng chú ý: khác biệt đáng chú ý:
 Named pipes tồn tại như là một device special Named pipes tồn tại như là một device special
file trong file system.file trong file system.
 Các tiến trình khác tổ tiên có thể chia sẽ data Các tiến trình khác tổ tiên có thể chia sẽ data
thông qua một named pipe.thông qua một named pipe.
 Khi tất cả I/O được hoàn tất bởi các tiến trình Khi tất cả I/O được hoàn tất bởi các tiến trình
chia sẻ, named pipe còn lưu lại trong file chia sẻ, named pipe còn lưu lại trong file
system để dùng sau. system để dùng sau.
Tạo FIFOTạo FIFO
 Có nhiều cách để tạo một named pipe. Hai Có nhiều cách để tạo một named pipe. Hai
cách đầu tiên là tạo trực tiếp từ shell.cách đầu tiên là tạo trực tiếp từ shell.
 mknod MYFIFO pmknod MYFIFO p
 mkfifo a=rw MYFIFOmkfifo a=rw MYFIFO
 FIFO files có thể được xác định trong FIFO files có thể được xác định trong
physical file system bởi ký tự “p” ở đầu tiên:physical file system bởi ký tự “p” ở đầu tiên:
[root@pascal root]# ls [root@pascal root]# ls l MYFIFOl MYFIFO
prwprw rr rr 1 root root 0 Aug 23 23:35 MYFIFO1 root root 0 Aug 23 23:35 MYFIFO
[root@pascal root]# [root@pascal root]#
Tạo FIFO trong CTạo FIFO trong C
 Để tạo FIFO trong C, ta có thể dùng Để tạo FIFO trong C, ta có thể dùng
mknod() system call:mknod() system call:

LIBRARY FUNCTION: mknod();LIBRARY FUNCTION: mknod();
PROTOTYPE: int mknod( char *pathname, PROTOTYPE: int mknod( char *pathname,
mode_t mode, dev_t dev);mode_t mode, dev_t dev);
RETURNS: 0 on success,RETURNS: 0 on success,
1 on error:errno=EFAULT (pathname invalid)1 on error:errno=EFAULT (pathname invalid)
 NOTES: Tạo filesystem node (file, device file, or FIFO) NOTES: Tạo filesystem node (file, device file, or FIFO)
EACCES (permission denied)EACCES (permission denied)
ENAMETOOLONG (pathname ENAMETOOLONG (pathname
too long)too long)
ENOENT (invalid pathname)ENOENT (invalid pathname)
ENOTDIR (invalid pathname)ENOTDIR (invalid pathname)
mknodmknod
 Muốn biến rõ hơn về mknod thì hãy dùng lệnh Muốn biến rõ hơn về mknod thì hãy dùng lệnh
manman,nhưng xét ví dụ đơn giản sau trong C:,nhưng xét ví dụ đơn giản sau trong C:
 mknod("/tmp/MYFIFO", S_IFIFO|0666, 0);mknod("/tmp/MYFIFO", S_IFIFO|0666, 0);
 Ở đây, file “/tmp/MYFIFO” được tạo ra như là Ở đây, file “/tmp/MYFIFO” được tạo ra như là
một FIFO file. Quyền của file là “0666”, mặc dù một FIFO file. Quyền của file là “0666”, mặc dù
chúng bị ảnh hưởng bởi umask setting như sau:chúng bị ảnh hưởng bởi umask setting như sau:
 final_umask = requested_permissions & final_umask = requested_permissions &
˜original_umask˜original_umask
 Một mẹo nhỏ dùng umask() system call để tạm Một mẹo nhỏ dùng umask() system call để tạm
thời vô hiệu giá trị umask :thời vô hiệu giá trị umask :
 umask(0);umask(0);
 mknod("/tmp/MYFIFO", S_IFIFO|0666, 0);mknod("/tmp/MYFIFO", S_IFIFO|0666, 0);
Thao tác FIFO Thao tác FIFO
 Các thao tác I/O trên FIFO là cần thiết như đối Các thao tác I/O trên FIFO là cần thiết như đối
với các pipe thông thường, với một ngoại lệ với các pipe thông thường, với một ngoại lệ
chính yếu. Một “open” system call hay hàm thư chính yếu. Một “open” system call hay hàm thư
viện cần phải được dùng để physically open up viện cần phải được dùng để physically open up
một kênh tới pipe. Với halfmột kênh tới pipe. Với half duplex pipes, điều duplex pipes, điều

này là không cần thiết, bởi vì khi đó pipe nằm này là không cần thiết, bởi vì khi đó pipe nằm
trong kernel và không phải trên physical trong kernel và không phải trên physical
filesystem. Trong ví dụ, chúng ta sẽ xem như filesystem. Trong ví dụ, chúng ta sẽ xem như
pipe là một stream, mở nó ra với fopen() và pipe là một stream, mở nó ra với fopen() và
đóng với fclose().đóng với fclose().
fifoserver.cfifoserver.c
 #include <stdio.h>#include <stdio.h>
 #include <stdlib.h>#include <stdlib.h>
 #include <sys/stat.h>#include <sys/stat.h>
 #include <unistd.h>#include <unistd.h>
 #include <linux/stat.h>#include <linux/stat.h>
 #define FIFO_FILE "MYFIFO"#define FIFO_FILE "MYFIFO"
 int main(void)int main(void)
 {{
 FILE *fp;FILE *fp;
 char readbuf[80];char readbuf[80];
 /* Create the FIFO if it does not exist *//* Create the FIFO if it does not exist */
 umask(0);umask(0);
 mknod(FIFO_FILE, S_IFIFO|0666, 0);mknod(FIFO_FILE, S_IFIFO|0666, 0);
fifoserver.c (tt)fifoserver.c (tt)
 while(1)while(1)
 {{
 fp = fopen(FIFO_FILE, "r");fp = fopen(FIFO_FILE, "r");
 fgets(readbuf, 80, fp);fgets(readbuf, 80, fp);
 printf("Received string: %sprintf("Received string: %s\\n", readbuf);n", readbuf);
 fclose(fp);fclose(fp);
 }}
 return(0);return(0);
 }}
fifoclient.cfifoclient.c

 #include <stdio.h>#include <stdio.h>
 #include <stdlib.h>#include <stdlib.h>
 #define FIFO_FILE "MYFIFO"#define FIFO_FILE "MYFIFO"
 int main(int argc, char *argv[])int main(int argc, char *argv[])
 {{
 FILE *fp;FILE *fp;
 if ( argc != 2 ) {if ( argc != 2 ) {
 printf("USAGE: fifoclient [string]printf("USAGE: fifoclient [string]\\n");n");
 exit(1);exit(1);
 }}

×