linux系统调用

系统调用是作为异常处理的,同其它异常处理handler类似,主要分为三步:
1、保存现场环境(保存各寄存器的值到内核堆栈中)
2、调用相应的系统调用处理函数
3、恢复现场环境,并由内核态切换回用户态

可通过两种方式来调用system call:
1、int 0x80
2、sysenter
这里主要讨论第一种方式

以x86为例:
0x80软中断的handler在trap_init中初始化:start_kernel->trap_init->system_call

963         set_system_trap_gate(SYSCALL_VECTOR, &system_call);

system_call在arch/x86/kernel/entry_32.S中定义:

516         # system call handler stub
 517 ENTRY(system_call)
 518         RING0_INT_FRAME                 # can't unwind into user space anyway
 519         pushl %eax                      # save orig_eax
 520         CFI_ADJUST_CFA_OFFSET 4
 521         SAVE_ALL
 522         GET_THREAD_INFO(%ebp)
 523                                         # system call tracing in operation / emulation
 524         testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
 525         jnz syscall_trace_entry
 526         cmpl $(nr_syscalls), %eax
 527         jae syscall_badsys
 528 syscall_call:
 529         call *sys_call_table(,%eax,4)
 530         movl %eax,PT_EAX(%esp)          # store the return value
 531 syscall_exit:
 532         LOCKDEP_SYS_EXIT
 533         DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
 534                                         # setting need_resched or sigpending
 535                                         # between sampling and the iret
 536         TRACE_IRQS_OFF
 537         movl TI_flags(%ebp), %ecx
 538         testl $_TIF_ALLWORK_MASK, %ecx  # current->work
 539         jne syscall_exit_work
 540 
 541 restore_all:
 542         TRACE_IRQS_IRET


1、SAVE_ALL做现场保护
2、call *sys_call_table(,%eax,4)调用相应的系统调用;sys_call_table在arch/x86/kernel/syscall_table_32.S中定义
3、syscall_exit_work恢复现场

主要的处理流程如下图所示:

signal对system call的影响:
有一类系统调用不能立即完成,可能阻塞当前调用进程,将进程状态置为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE。
当进程处于TASK_INTERRUPTIBLE状态,收到其它进程发给它的signal时,内核会将该进程置为TASK_RUNNING,进程可以被调度并重新运行;这样就导致了系统调用还没有完成,并返回 EINTR, ERESTARTNOHAND, ERESTART_RESTARTBLOCK, ERESTARTSYS, 或 ERESTARTNOINTR等错误码

当上述情况出现时,内核根据错误码做不同的处理:
1、结束系统调用,并从系统调用的下一条指令执行
2、重新执行,返回到用户空间后重新执行系统调用指令
3、看情况,如果信号设置了SA_RESTART标志,则重新执行;否则,返回EINTR错误码,并结束系统调用

系统调用的重启:
do_notify_resume->do_signal(arch/x86/kernel/signal.c)

824         /* Did we come from a system call? */
825         if (syscall_get_nr(current, regs) >= 0) {
826                 /* Restart the system call - no handlers present */
827                 switch (syscall_get_error(current, regs)) {
828                 case -ERESTARTNOHAND:
829                 case -ERESTARTSYS:
830                 case -ERESTARTNOINTR:
831                         regs->ax = regs->orig_ax;
832                         regs->ip -= 2;
833                         break;
834 
835                 case -ERESTART_RESTARTBLOCK:
836                         regs->ax = NR_restart_syscall;
837                         regs->ip -= 2;
838                         break;
839                 }
840         }

regs->ax存放的是系统调用服务函数返回值,regs->orig_ax存放的是系统调用编号;而ip指向系统调用的下一条指令,由于int 0x80/sysenter均为两字节,减2后则ip重新指向int 0x80或sysenter
重启系统调用分两种情况:一种是重新调用原系统调用,另一种是调用restart_syscall系统调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值