|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | * Copyright (C) Nginx, Inc. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <sys/syscall.h> | 
|  | #include <machine/asm.h> | 
|  |  | 
|  | /* | 
|  | * rfork_thread(3) - rfork_thread(flags, stack, func, arg); | 
|  | */ | 
|  |  | 
|  | #define	KERNCALL	int $0x80 | 
|  |  | 
|  | ENTRY(rfork_thread) | 
|  | push	%ebp | 
|  | mov	%esp, %ebp | 
|  | push	%esi | 
|  |  | 
|  | mov	12(%ebp), %esi	# the thread stack address | 
|  |  | 
|  | sub	$4, %esi | 
|  | mov	20(%ebp), %eax	# the thread argument | 
|  | mov	%eax, (%esi) | 
|  |  | 
|  | sub	$4, %esi | 
|  | mov	16(%ebp), %eax	# the thread start address | 
|  | mov	%eax, (%esi) | 
|  |  | 
|  | push	8(%ebp)		# rfork(2) flags | 
|  | push	$0 | 
|  | mov	$SYS_rfork, %eax | 
|  | KERNCALL | 
|  | jc	error | 
|  |  | 
|  | cmp	$0, %edx | 
|  | jne	child | 
|  |  | 
|  | parent: | 
|  | add	$8, %esp | 
|  | pop	%esi | 
|  | leave | 
|  | ret | 
|  |  | 
|  | child: | 
|  | mov	%esi, %esp | 
|  | pop	%eax | 
|  | call	*%eax		# call a thread start address ... | 
|  | add	$4, %esp | 
|  |  | 
|  | push	%eax | 
|  | push	$0 | 
|  | mov	$SYS_exit, %eax	# ... and exit(2) after a thread would return | 
|  | KERNCALL | 
|  |  | 
|  | error: | 
|  | add	$8, %esp | 
|  | pop	%esi | 
|  | leave | 
|  | PIC_PROLOGUE | 
|  |  | 
|  | /* libc's cerror: jmp  PIC_PLT(HIDENAME(cerror)) */ | 
|  |  | 
|  | push	%eax | 
|  | call	PIC_PLT(CNAME(__error)) | 
|  | pop	%ecx | 
|  | PIC_EPILOGUE | 
|  | mov	%ecx, (%eax) | 
|  | mov	$-1, %eax | 
|  | mov	$-1, %edx | 
|  | ret |