系统调用

内核提供了用户进程和内核交互的接口,使得应用程序可以受限制的访问硬件设备。

提供这些接口主要是为了保证系统稳定可靠,避免应用程序恣意妄行。

一、内核通信

系统调用在用户空间进程和硬件设备之间添加中间才能。作用有三:

  • 为用户空间提供一种硬件的抽象接口。无需理会物理结构是怎么样的。
  • 系统调用保证了系统的稳定和安全。内核可以有选择的对其访问进行控制。
  • 每个进程都运行在虚拟系统中,用户空间和系统的其余部分提供这样一层公共接口。

二、API、POSIX和C库

API:应用程序不需要访问内核,编程接口可以组合成API

POSIX:依据大多数Unix系统接口建立的

C库:提供了Unix主要API,所有C程序都可以使用C库

三、系统调用

例如,getpid中的系统调用:

SYSCALL_DEFINE0(getpid)
{return task_tgid_vnr(current);    //returns current->tgid
}

SYSCALL_DEFINE0只是一个宏,它定义一个无参数的系统调用(因此数字0),展开后代码如下:

asmlinkage long sys_getpid(void)

asmlinkage是一个限定词,是一个编译指令,通知编译器仅从栈中提取该函数的参数。

3.1 系统调用号

在Linux中,每个系统调用被附于一个系统调用号。

系统调用号,一旦分配就不能在更改,否则编译好的应用程序会崩溃。

Linux中有一个"未实现"系统调用sys_ni_syscall(),会返回-ENOSYS。

内核记录了系统调用表中所有已注册过的系统调用的列表,存储在sys_call_table中。定义于arch/i386/kernel/syscall_64.c

3.2 系统调用的性能

Linux系统调用比其他操作系统执行的要快,上下文切换时间是一个重要的原因,内核都被优化的简洁高效。

四、系统调用处理程序

通知内核的机制是靠软中断实现的:通过引发一个异常来促使系统切换到内核态去执行异常处理程序。

此时的异常处理程序就是系统调用处理程序。程序名字叫system_call(),并且与硬件系统密切相关。

system_call()通过将给定的系统调用号与NR_syscalls作比较来检查有效性。如果它大于或者等于NR_syscalls,该函数就返回-ENOSYS。否则执行系统调用

call *sys_call_table(, %rax, 8)

4.2 参数传递

参数依次用ebx、ecx、edx、esi和edi的顺序存放前5个参数。

需要六个或六个以上参数的情况不多见,此时,应该用一个单独的寄存器存放指向所有这些参数在用户空间地址的指针。

五、系统调用的实现

怎样设计和实现一个系统调用是难题所在,而把它加到内核里却无须太多周折。

5.1 实现系统调用

Linux中不提倡采用多用途的系统调用(一个系统调用通过传递不同的参数值来选择完成不同的工作)。

  • 系统调用的接口应该力求简介,参数尽可能少。并且力求稳定,不做改动。
  • 设计接口的时候要尽量为将来多做考虑,系统调用设计的越通用越好。
  • 要时刻注意可移植性和健壮性。

5.2 参数验证

如果用户将不合法的输入传递给内核,那么系统的安全和稳定将面临极大的考验。

最重要的检查就是检查用户提供的指针是否有效,在接收用户空间的指针之前,内核必须保证:

  • 指针指向的内存区是用户空间,进程决不能哄骗内核去读其他进程的数据。
  • 指针知悉将发的内存区域在进程的地址空间里,进程决不能哄骗内核去读其他进程的数据。
  • 如果是读,该内存应被标记为可读;如果是写,该内存应被标记为可写;如果可执行,该内存应被标记为可执行。进程不能绕过内存访问限制。

向用户空间写入数据,内核提供了copy_to_user(),第一个参数是进程空间中的目的内存地址。第二个参数是内核空间的源地址,最后一个是数据长度。

从用户空间读取数据,内核提供了copy_from_user(),把第二个参数拷贝到第一个参数中,第三个参数是数据长度

SYSCALL_DEFINE4(reboot,int, magic1,int, magic2,unsigned int, cmd,void __user *, arg)
{char buffer[256];/* 我们只信任启动系统的系统管理员 */if(!capable(CAP_SYS_BOOT))return -EPERM;/* 为了安全起见,我们需要"magic"参数 */if(magic1 != LINUX_REBOOT_MAGIC1 ||(magic2 != LINUX_REBOOT_MAGIC2 &&magic2 != LINUX_REBOOT_MAGIC2A &&magic2 != LINUX_REBOOT_MAGIC2B &&magic2 != LINUX_REBOOT_MAGIC2C))return -EINVAL;/* 当未设置pm_power_off时,请不要试图让power_off的代码看起来像是可以停机* 而应该采用更简单的方式 */if((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)cmd = LINUX_REBOOT_CMD_HALT;lock_kernel();switch(cmd) {case LINUX_REBOOT_CMD_RESTART:kernel_restart(NULL);break;case LINUX_REBOOT_CMD_CAD_ON:C_A_D = 1;break;case LINUX_REBOOT_CMD_CAD_OFF:C_A_D = 0;break;case LINUX_REBOOT_CMD_HALT:kernel_halt();unlock_kernel();do_exit(0);break;case LINUX_REBOOT_CMD_POWER_OFF:kernel_power_off();unlock_kernel();do_exit(0);break;case LINUX_REBOOT_CMD_RESTART2:if(strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {unlock_kernel();return -EFAULT;}buffer[sizeof(buffer) - 1] = '\0';kernel_restart(buffer);break;default:unlock_kernel();return -EINVAL;}unlock_kernel();return 0;
}

SYSCALL_DEFINE4

具体capable()的权能和其对应的权限列表,可以在<linux/capability.h>中找到

六、系统上下文调用

在进程上下文中,内核可以休眠(比如系统调用阻塞或显式调用schedule()的时候),并且可以抢占

能够休眠说明系统调用可以使用内核提供 ,休眠能力能给编程极大便利。

当系统调用返回的时候,控制权任然在system_call()中,最终会负责切换到用户空间,并且用户进程继续执行下去。

6.1 绑定一个系统调用的最后步骤

当编写完一个系统调用后,把注册成一个正式的系统调用是件琐碎的工作:

1)在系统调用表的最后加入一个表项。从0开始算起,系统调用在该表中的位置就是它的系统调用号

2)对于所支持的各种体系结构,系统调用号都必须定义于<asm/unistd.h>中

3)系统调用必须被编译进内核映象(不能被编译成模块)。只要把它放进kernel/下的一个相关的文件中就可以了,比如sys.c包含了各种各样的系统调用。

文中说在entry.s中,可能是x86结构。然而我看得是4412的内核,在 arch/arm/kernel/call.S :

/**  linux/arch/arm/kernel/calls.S**  Copyright (C) 1995-2005 Russell King** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.**  This file is included thrice in entry-common.S*/
/* 0 */        CALL(sys_restart_syscall)CALL(sys_exit)CALL(sys_fork_wrapper)CALL(sys_read)CALL(sys_write)
/* 5 */        CALL(sys_open)CALL(sys_close)CALL(sys_ni_syscall)        /* was sys_waitpid */CALL(sys_creat)CALL(sys_link)
/* 10 */    CALL(sys_unlink)CALL(sys_execve_wrapper)CALL(sys_chdir)CALL(OBSOLETE(sys_time))    /* used by libc4 */CALL(sys_mknod)
/* 15 */    CALL(sys_chmod)CALL(sys_lchown16)CALL(sys_ni_syscall)        /* was sys_break */CALL(sys_ni_syscall)        /* was sys_stat */CALL(sys_lseek)
/* 20 */    CALL(sys_getpid)CALL(sys_mount)CALL(OBSOLETE(sys_oldumount))    /* used by libc4 */CALL(sys_setuid16)CALL(sys_getuid16)
/* 25 */    CALL(OBSOLETE(sys_stime))CALL(sys_ptrace)CALL(OBSOLETE(sys_alarm))    /* used by libc4 */CALL(sys_ni_syscall)        /* was sys_fstat */CALL(sys_pause)
/* 30 */    CALL(OBSOLETE(sys_utime))    /* used by libc4 */CALL(sys_ni_syscall)        /* was sys_stty */CALL(sys_ni_syscall)        /* was sys_getty */CALL(sys_access)CALL(sys_nice)
/* 35 */    CALL(sys_ni_syscall)        /* was sys_ftime */CALL(sys_sync)CALL(sys_kill)CALL(sys_rename)CALL(sys_mkdir)
/* 40 */    CALL(sys_rmdir)CALL(sys_dup)CALL(sys_pipe)CALL(sys_times)CALL(sys_ni_syscall)        /* was sys_prof */
/* 45 */    CALL(sys_brk)CALL(sys_setgid16)CALL(sys_getgid16)CALL(sys_ni_syscall)        /* was sys_signal */CALL(sys_geteuid16)
/* 50 */    CALL(sys_getegid16)CALL(sys_acct)CALL(sys_umount)CALL(sys_ni_syscall)        /* was sys_lock */CALL(sys_ioctl)
/* 55 */    CALL(sys_fcntl)CALL(sys_ni_syscall)        /* was sys_mpx */CALL(sys_setpgid)CALL(sys_ni_syscall)        /* was sys_ulimit */CALL(sys_ni_syscall)        /* was sys_olduname */
/* 60 */    CALL(sys_umask)CALL(sys_chroot)CALL(sys_ustat)CALL(sys_dup2)CALL(sys_getppid)
/* 65 */    CALL(sys_getpgrp)CALL(sys_setsid)CALL(sys_sigaction)CALL(sys_ni_syscall)        /* was sys_sgetmask */CALL(sys_ni_syscall)        /* was sys_ssetmask */
/* 70 */    CALL(sys_setreuid16)CALL(sys_setregid16)CALL(sys_sigsuspend)CALL(sys_sigpending)CALL(sys_sethostname)
/* 75 */    CALL(sys_setrlimit)CALL(OBSOLETE(sys_old_getrlimit)) /* used by libc4 */CALL(sys_getrusage)CALL(sys_gettimeofday)CALL(sys_settimeofday)
/* 80 */    CALL(sys_getgroups16)CALL(sys_setgroups16)CALL(OBSOLETE(sys_old_select))    /* used by libc4 */CALL(sys_symlink)CALL(sys_ni_syscall)        /* was sys_lstat */
/* 85 */    CALL(sys_readlink)CALL(sys_uselib)CALL(sys_swapon)CALL(sys_reboot)CALL(OBSOLETE(sys_old_readdir))    /* used by libc4 */
/* 90 */    CALL(OBSOLETE(sys_old_mmap))    /* used by libc4 */CALL(sys_munmap)CALL(sys_truncate)CALL(sys_ftruncate)CALL(sys_fchmod)
/* 95 */    CALL(sys_fchown16)CALL(sys_getpriority)CALL(sys_setpriority)CALL(sys_ni_syscall)        /* was sys_profil */CALL(sys_statfs)
/* 100 */    CALL(sys_fstatfs)CALL(sys_ni_syscall)        /* sys_ioperm */CALL(OBSOLETE(ABI(sys_socketcall, sys_oabi_socketcall)))CALL(sys_syslog)CALL(sys_setitimer)
/* 105 */    CALL(sys_getitimer)CALL(sys_newstat)CALL(sys_newlstat)CALL(sys_newfstat)CALL(sys_ni_syscall)        /* was sys_uname */
/* 110 */    CALL(sys_ni_syscall)        /* was sys_iopl */CALL(sys_vhangup)CALL(sys_ni_syscall)CALL(OBSOLETE(sys_syscall))    /* call a syscall */CALL(sys_wait4)
/* 115 */    CALL(sys_swapoff)CALL(sys_sysinfo)CALL(OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)))CALL(sys_fsync)CALL(sys_sigreturn_wrapper)
/* 120 */    CALL(sys_clone_wrapper)CALL(sys_setdomainname)CALL(sys_newuname)CALL(sys_ni_syscall)        /* modify_ldt */CALL(sys_adjtimex)
/* 125 */    CALL(sys_mprotect)CALL(sys_sigprocmask)CALL(sys_ni_syscall)        /* was sys_create_module */CALL(sys_init_module)CALL(sys_delete_module)
/* 130 */    CALL(sys_ni_syscall)        /* was sys_get_kernel_syms */CALL(sys_quotactl)CALL(sys_getpgid)CALL(sys_fchdir)CALL(sys_bdflush)
/* 135 */    CALL(sys_sysfs)CALL(sys_personality)CALL(sys_ni_syscall)        /* reserved for afs_syscall */CALL(sys_setfsuid16)CALL(sys_setfsgid16)
/* 140 */    CALL(sys_llseek)CALL(sys_getdents)CALL(sys_select)CALL(sys_flock)CALL(sys_msync)
/* 145 */    CALL(sys_readv)CALL(sys_writev)CALL(sys_getsid)CALL(sys_fdatasync)CALL(sys_sysctl)
/* 150 */    CALL(sys_mlock)CALL(sys_munlock)CALL(sys_mlockall)CALL(sys_munlockall)CALL(sys_sched_setparam)
/* 155 */    CALL(sys_sched_getparam)CALL(sys_sched_setscheduler)CALL(sys_sched_getscheduler)CALL(sys_sched_yield)CALL(sys_sched_get_priority_max)
/* 160 */    CALL(sys_sched_get_priority_min)CALL(sys_sched_rr_get_interval)CALL(sys_nanosleep)CALL(sys_mremap)CALL(sys_setresuid16)
/* 165 */    CALL(sys_getresuid16)CALL(sys_ni_syscall)        /* vm86 */CALL(sys_ni_syscall)        /* was sys_query_module */CALL(sys_poll)CALL(sys_nfsservctl)
/* 170 */    CALL(sys_setresgid16)CALL(sys_getresgid16)CALL(sys_prctl)CALL(sys_rt_sigreturn_wrapper)CALL(sys_rt_sigaction)
/* 175 */    CALL(sys_rt_sigprocmask)CALL(sys_rt_sigpending)CALL(sys_rt_sigtimedwait)CALL(sys_rt_sigqueueinfo)CALL(sys_rt_sigsuspend)
/* 180 */    CALL(ABI(sys_pread64, sys_oabi_pread64))CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))CALL(sys_chown16)CALL(sys_getcwd)CALL(sys_capget)
/* 185 */    CALL(sys_capset)CALL(sys_sigaltstack_wrapper)CALL(sys_sendfile)CALL(sys_ni_syscall)        /* getpmsg */CALL(sys_ni_syscall)        /* putpmsg */
/* 190 */    CALL(sys_vfork_wrapper)CALL(sys_getrlimit)CALL(sys_mmap2)CALL(ABI(sys_truncate64, sys_oabi_truncate64))CALL(ABI(sys_ftruncate64, sys_oabi_ftruncate64))
/* 195 */    CALL(ABI(sys_stat64, sys_oabi_stat64))CALL(ABI(sys_lstat64, sys_oabi_lstat64))CALL(ABI(sys_fstat64, sys_oabi_fstat64))CALL(sys_lchown)CALL(sys_getuid)
/* 200 */    CALL(sys_getgid)CALL(sys_geteuid)CALL(sys_getegid)CALL(sys_setreuid)CALL(sys_setregid)
/* 205 */    CALL(sys_getgroups)CALL(sys_setgroups)CALL(sys_fchown)CALL(sys_setresuid)CALL(sys_getresuid)
/* 210 */    CALL(sys_setresgid)CALL(sys_getresgid)CALL(sys_chown)CALL(sys_setuid)CALL(sys_setgid)
/* 215 */    CALL(sys_setfsuid)CALL(sys_setfsgid)CALL(sys_getdents64)CALL(sys_pivot_root)CALL(sys_mincore)
/* 220 */    CALL(sys_madvise)CALL(ABI(sys_fcntl64, sys_oabi_fcntl64))CALL(sys_ni_syscall) /* TUX */CALL(sys_ni_syscall)CALL(sys_gettid)
/* 225 */    CALL(ABI(sys_readahead, sys_oabi_readahead))CALL(sys_setxattr)CALL(sys_lsetxattr)CALL(sys_fsetxattr)CALL(sys_getxattr)
/* 230 */    CALL(sys_lgetxattr)CALL(sys_fgetxattr)CALL(sys_listxattr)CALL(sys_llistxattr)CALL(sys_flistxattr)
/* 235 */    CALL(sys_removexattr)CALL(sys_lremovexattr)CALL(sys_fremovexattr)CALL(sys_tkill)CALL(sys_sendfile64)
/* 240 */    CALL(sys_futex)CALL(sys_sched_setaffinity)CALL(sys_sched_getaffinity)CALL(sys_io_setup)CALL(sys_io_destroy)
/* 245 */    CALL(sys_io_getevents)CALL(sys_io_submit)CALL(sys_io_cancel)CALL(sys_exit_group)CALL(sys_lookup_dcookie)
/* 250 */    CALL(sys_epoll_create)CALL(ABI(sys_epoll_ctl, sys_oabi_epoll_ctl))CALL(ABI(sys_epoll_wait, sys_oabi_epoll_wait))CALL(sys_remap_file_pages)CALL(sys_ni_syscall)    /* sys_set_thread_area */
/* 255 */    CALL(sys_ni_syscall)    /* sys_get_thread_area */CALL(sys_set_tid_address)CALL(sys_timer_create)CALL(sys_timer_settime)CALL(sys_timer_gettime)
/* 260 */    CALL(sys_timer_getoverrun)CALL(sys_timer_delete)CALL(sys_clock_settime)CALL(sys_clock_gettime)CALL(sys_clock_getres)
/* 265 */    CALL(sys_clock_nanosleep)CALL(sys_statfs64_wrapper)CALL(sys_fstatfs64_wrapper)CALL(sys_tgkill)CALL(sys_utimes)
/* 270 */    CALL(sys_arm_fadvise64_64)CALL(sys_pciconfig_iobase)CALL(sys_pciconfig_read)CALL(sys_pciconfig_write)CALL(sys_mq_open)
/* 275 */    CALL(sys_mq_unlink)CALL(sys_mq_timedsend)CALL(sys_mq_timedreceive)CALL(sys_mq_notify)CALL(sys_mq_getsetattr)
/* 280 */    CALL(sys_waitid)CALL(sys_socket)CALL(ABI(sys_bind, sys_oabi_bind))CALL(ABI(sys_connect, sys_oabi_connect))CALL(sys_listen)
/* 285 */    CALL(sys_accept)CALL(sys_getsockname)CALL(sys_getpeername)CALL(sys_socketpair)CALL(sys_send)
/* 290 */    CALL(ABI(sys_sendto, sys_oabi_sendto))CALL(sys_recv)CALL(sys_recvfrom)CALL(sys_shutdown)CALL(sys_setsockopt)
/* 295 */    CALL(sys_getsockopt)CALL(ABI(sys_sendmsg, sys_oabi_sendmsg))CALL(sys_recvmsg)CALL(ABI(sys_semop, sys_oabi_semop))CALL(sys_semget)
/* 300 */    CALL(sys_semctl)CALL(sys_msgsnd)CALL(sys_msgrcv)CALL(sys_msgget)CALL(sys_msgctl)
/* 305 */    CALL(sys_shmat)CALL(sys_shmdt)CALL(sys_shmget)CALL(sys_shmctl)CALL(sys_add_key)
/* 310 */    CALL(sys_request_key)CALL(sys_keyctl)CALL(ABI(sys_semtimedop, sys_oabi_semtimedop))
/* vserver */    CALL(sys_ni_syscall)CALL(sys_ioprio_set)
/* 315 */    CALL(sys_ioprio_get)CALL(sys_inotify_init)CALL(sys_inotify_add_watch)CALL(sys_inotify_rm_watch)CALL(sys_mbind)
/* 320 */    CALL(sys_get_mempolicy)CALL(sys_set_mempolicy)CALL(sys_openat)CALL(sys_mkdirat)CALL(sys_mknodat)
/* 325 */    CALL(sys_fchownat)CALL(sys_futimesat)CALL(ABI(sys_fstatat64,  sys_oabi_fstatat64))CALL(sys_unlinkat)CALL(sys_renameat)
/* 330 */    CALL(sys_linkat)CALL(sys_symlinkat)CALL(sys_readlinkat)CALL(sys_fchmodat)CALL(sys_faccessat)
/* 335 */    CALL(sys_pselect6)CALL(sys_ppoll)CALL(sys_unshare)CALL(sys_set_robust_list)CALL(sys_get_robust_list)
/* 340 */    CALL(sys_splice)CALL(sys_sync_file_range2)CALL(sys_tee)CALL(sys_vmsplice)CALL(sys_move_pages)
/* 345 */    CALL(sys_getcpu)CALL(sys_epoll_pwait)CALL(sys_kexec_load)CALL(sys_utimensat)CALL(sys_signalfd)
/* 350 */    CALL(sys_timerfd_create)CALL(sys_eventfd)CALL(sys_fallocate)CALL(sys_timerfd_settime)CALL(sys_timerfd_gettime)
/* 355 */    CALL(sys_signalfd4)CALL(sys_eventfd2)CALL(sys_epoll_create1)CALL(sys_dup3)CALL(sys_pipe2)
/* 360 */    CALL(sys_inotify_init1)CALL(sys_preadv)CALL(sys_pwritev)CALL(sys_rt_tgsigqueueinfo)CALL(sys_perf_event_open)
/* 365 */    CALL(sys_recvmmsg)CALL(sys_accept4)CALL(sys_fanotify_init)CALL(sys_fanotify_mark)CALL(sys_prlimit64)
/* 370 */    CALL(sys_name_to_handle_at)CALL(sys_open_by_handle_at)CALL(sys_clock_adjtime)CALL(sys_syncfs)CALL(sys_sendmmsg)
/* 375 */    CALL(sys_setns)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
#endif
.rept syscalls_paddingCALL(sys_ni_syscall)
.endr

syscall表

要把新的系统调用加到这个表的末尾。

接下来我们要把系统调用号加入到<asm/unistd.h>中,它的格式如下:

/** This file contains the system call numbers.*/#define __NR_restart_syscall        (__NR_SYSCALL_BASE+  0)
#define __NR_exit            (__NR_SYSCALL_BASE+  1)
#define __NR_fork            (__NR_SYSCALL_BASE+  2)
#define __NR_read            (__NR_SYSCALL_BASE+  3)
#define __NR_write            (__NR_SYSCALL_BASE+  4)
#define __NR_open            (__NR_SYSCALL_BASE+  5)
#define __NR_close            (__NR_SYSCALL_BASE+  6)#define __NR_name_to_handle_at        (__NR_SYSCALL_BASE+370)
#define __NR_open_by_handle_at        (__NR_SYSCALL_BASE+371)
#define __NR_clock_adjtime        (__NR_SYSCALL_BASE+372)
#define __NR_syncfs            (__NR_SYSCALL_BASE+373)
#define __NR_sendmmsg            (__NR_SYSCALL_BASE+374)
#define __NR_setns            (__NR_SYSCALL_BASE+375)

asm/unistd.h

加入一项比如:#define __NR_foo 338

4)然后它是实现函数,可以放在最紧密关联的代码中去。比如功能和调度相关,可以放在sched.c中

#include <asm/page.h>
/** sys_foo - 每个人喜欢的系统调用*/
asmlinkage long sys_foo(void)
{return THREAD_SIZE;
}

sys_foo

6.2 用户空间访问系统调用

通常,系统调用靠C库支持。用户程序通过包含标准头文件并和C库链接,就可以使用系统调用。

Linux本身提供共了一组宏,用于直接对系统调用进行访问。它会设置好寄存器并调用陷入指令。这些宏是_syscalln(),其中n范围是0到6,代表需要传递给系统调用的参数个数。

long open(const char *filename, int flags, int mode)
/* 而不靠库支持,直接调用从此系统调用的宏形式为 */
#define NR_open 5
_syscall3(long, open, const char *, filename, int, flags, int, mode)
/* 这样应用程序就可以直接使用open */

open系统调用例子

对于每个宏来说,都有2+2xn个参数。第一个参数对应着系统调用的返回值类型。第二个参数是系统调用的名称。再以后是按照系统调用参数的顺序排列的每个参数的类型和名称。

然后是foo()调用的测试代码:

#define __NR_foo 283
__syscall0(long, foo)int main()
{long stack_size;stack_size = foo();printf("The kernel stack size is %ld\n", stack_size);return 0;
}

__NR_foo

6.3 为什么不通过系统调用的方式实现

尽管建立一个新的系统调用非常容易,但不提倡这么做。通常都会有更好的办法用来代替新建一个系统调用以作实现。

建立一个新的系统调用的好处:

  • 系统调用创建容易且使用方便。
  • Linux系统调用的高性能显而易见。

问题是:

  • 你需要一个系统调用号,而这个需要一个内核在处于开发版本的时候由官方分配给你
  • 系统调用被加入稳定内核后就被固化了,为了避免应用程序的崩溃,它的接口不允许做改动
  • 需要将系统调用分别注册到每个需要支持的体系结构中去
  • 在脚本中不容易条用系统调用,也不能从文件系统直接访问系统调用
  • 由于你需要系统调用号,因此在主内核树之外是很难维护和使用系统调用的
  • 如果仅仅进行简单的信息交换,系统调用就大材小用了

替代方法:

  • 实现一个设备节点,并对此实现read()和write()。使用ioctl()对特定的设置进行操作或者对特定的信息进行检索。
  • 像信号量这样的某些接口,可以用文件描述符来表示,因此就可以按上述方式对其进行操作。
  • 把增加的信息作为一个文件放在sysfs的合适位置。

转载于:https://www.cnblogs.com/ch122633/p/9982521.html

Linux内核设计与实现 总结笔记(第五章)系统调用相关推荐

  1. Linux内核设计与实现学习笔记目录

    **注:**这是别人的笔记,我只是把目录抄过来 <Linux内核设计与实现学习笔记> 1.<Linux内核设计与实现>读书笔记(一)-内核简介 2.<Linux内核设计与 ...

  2. Linux内核设计与实现(1)第一章:Linux内核简介

    Linux内核设计与实现(1)第一章:Linux内核简介 1. linux历史及与Unix关系 2. 内核组成 3. 用户空间和内核空间 4. 系统调用 5. 中断 6. Unix强大的原因 7. L ...

  3. 初探内核之《Linux内核设计与实现》笔记上

    内核简介  本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单. 2. 高 ...

  4. Linux内核设计与实现 读书笔记

    第二章 Linux内核 1 内核开发特点 1)内核编译时不能访问C库: 2)浮点数很难使用: 3)内核只有一个定长堆栈: 4)注意同步和并发. 第三章 进程管理 1 current宏:查找当前运行进程 ...

  5. 《奔跑吧Linux内核(第二版)》第五章笔记

    Linux内核采用宏内核架构,即操作系统的大部分功能都在内核中实现,比如进程管理.内存管理.进程调度.设备管理等,并且都在特权模式下(内核空间)运行.而与之相反的另一种流行的架构是微内核架构,它把操作 ...

  6. linux内核设计与实现看不懂,Linux内核设计与实现读书笔记

    Unix强大的根本原因: Unix简洁, 提供几百个系统调用, 设计目的明确 Unix中 所有东西都被当做文件对待 Unix内核和相关系统工具是用C语言开发的, 移植能力强大 Unix进程创建迅速, ...

  7. 进程调度(一)--linux内核设计与实现读书笔记

    进程的调度程序是保证进程能有效工作的一个内核子系统.调度程序负责决定将哪个进程投入运行,何时运行以及运行多少时间.简单的来说,调度程序就是在给一堆就绪的进程分配处理器的时间,调度程序是多任务操作系统的 ...

  8. Linux内核设计与实现读书笔记

    1.进程管理 内核通过task_struct管理进程. 2.进程调度 1.可执行队列runqueue. 2.用户抢占.从中断返回或者系统调用返回的时候发生. 3.系统调用 1.系统调用参数放在寄存器里 ...

  9. linux+模块与设备关系,linux内核设计与实现读书笔记——设备和模块

    一.设备类型 1.块设备 blkdev:以块为单位寻址,支持重定位(数据随机访问),通过块设备节点来访问. 2.字符设备cdev:不可寻址,提供数据流访问,通过字符设备节点访问. 3.网络设备:对网络 ...

最新文章

  1. Backtrack的安装配置
  2. Oralce-清除数据的两种思路
  3. NYOJ_5743Distribution(第八届河南省程序设计大赛)
  4. CodeForces - 731D 80-th Level Archeology(线段树+暴力/差分)
  5. java switch case怎么判断范围_【转】Java期末复习攻略!
  6. 奇奇怪怪的知识增加了,大括号的历史你知道吗?
  7. 【linux】linux一次杀死多个进程
  8. python super().__init__()_python——多继承使用super().__init__ 发生的状态
  9. python postmessage 鼠标_SilkTest高级进阶系列7-用PostMessage模拟鼠标
  10. ubuntu安装labelme
  11. rose 生产java代码m_rose 生成代码
  12. Ubuntu各版本下载安装知网论文阅读神器CAJViewer,并添加快捷图标启动方式
  13. 面试必备:零拷贝详解
  14. domcontentloaded事件和laod事件区别
  15. angular.js 错误: Error [$injector:unpr] 原因
  16. 新华社 | 郭为:IT构架创新助力中国金融科技创新之路
  17. VUE项目获取微信二维码 (返回了的是一个html)
  18. 客运行业发展现状分析
  19. 海思HI3518E整体框架认识
  20. GIS空间分析(七)—— 地理空间大数据

热门文章

  1. windows上的python能否在unix上使用_怎么用python在Windows系统下,生成UNIX格式文件
  2. ajax.call失效无请求,移动端ajax请求问题?
  3. centos 7 mysql随机密码_在centos中安装了mysql5.7之后解决不知道随机的密码的问题...
  4. layui按钮展开、_layui可折叠的组织架构树形图
  5. java serializable 源码_Java源码分析之-Serializable接口
  6. python从列表随机取出多个数据_【python】从数组随机取数据
  7. 不懂指针类型,7个例子给你讲明白
  8. C语言的10大基础算法
  9. C/C++开发游戏项目之《智能图形界面-贪吃蛇》
  10. Python3实现红黑树[上篇]