#define __NR_clone 120
#define
SYS_clone 120
/* int clone(int (*fn)(void *arg), void
*child_stack, int flags, void *arg,
pid_t *ptid, struct
user_desc *tls, pid_t *ctid); */
.text
ENTRY (BP_SYM
(__clone))
movl $-EINVAL,%eax
movl STACK(%esp),%ecx 新线程的栈由
child_stack给出 STACK是参数的位置, 其它参数类似
/* Insert the argument onto
the new stack. Make sure the new
thread is started with an
alignment of (mod 16). */
andl $0xfffffff0, %ecx
subl $28,%ecx
movl
ARG(%esp),%eax /* no negative argument counts */
movl
%eax,12(%ecx) ecx是子线程的栈地址, fn的参数先入
/* Save the function
pointer as the zeroth argument.
It will be popped off in the child in the ebx frobbing below. */
movl FUNC(%esp),%eax
movl %eax,8(%ecx) 接下来是fn
/*
Don't leak any information. */
movl $0,4(%ecx)
/*
Do the system call */
pushl %ebx
pushl %esi
pushl %edi
系统调用真正需要的参数, 它并不需要fn, 和fork类似接着执行,fn是随着__
clone函数的结束而被子线程执行
movl TLS+12(%esp),%esi
movl PTID+12(%esp),%edx
movl FLAGS+12(%esp),%ebx
movl CTID+12(%esp),%edi
movl $SYS_ify(clone),%eax
/* Remember the flag value. */
movl %ebx, (%ecx)
int $0x80
两个线程都同时到这里,只是栈指针不一样了, 对于子线程, ebx将保存fn的地址
popl %edi
popl %esi
popl %ebx
test %eax,%eax
jl SYSCALL_ERROR_LABEL
0: 子线程
jz L(thread_start)
L(pseudo_end):
父线程__clone返回
ret
L(thread_start):
/* Note: %esi is zero. */
movl %esi,%ebp /* terminate
the stack frame */
testl $CLONE_THREAD, %edi 只考虑Yes的情况
je L(newpid)
L(haspid):
call *%ebx 调用fn, fn返回之后将执行exit,
线程退出, 等价于exit(fn(arg)), NOT exit_group
movl %eax, %ebx
movl $SYS_ify(exit), %eax
ENTER_KERNEL
PSEUDO_END (BP_SYM (__clone))
weak_alias
(BP_SYM (__clone), BP_SYM (clone))