Blame src/process/ntapi_tt_fork.c

268ef4
/********************************************************/
268ef4
/*  ntapi: Native API core library                      */
268ef4
/*  Copyright (C) 2013--2016  Z. Gilboa                 */
268ef4
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
268ef4
/********************************************************/
268ef4
268ef4
#include <psxtypes/psxtypes.h>
268ef4
#include <ntapi/nt_atomic.h>
268ef4
#include <ntapi/nt_status.h>
268ef4
#include <ntapi/nt_object.h>
268ef4
#include <ntapi/nt_memory.h>
268ef4
#include <ntapi/nt_thread.h>
268ef4
#include <ntapi/nt_process.h>
268ef4
#include <ntapi/ntapi.h>
268ef4
#include "ntapi_impl.h"
268ef4
268ef4
static intptr_t	__fork_retry_stats  = 0;
268ef4
static intptr_t	__fork_resume_stats = 0;
268ef4
268ef4
static int32_t __stdcall __fork_thread(void * ctx)
268ef4
{
268ef4
	intptr_t *	pstate;
268ef4
	intptr_t	state;
268ef4
	void *		hready;
268ef4
268ef4
	pstate = (intptr_t *)ctx;
268ef4
	state  = *pstate;
268ef4
	hready = (void *)state;
268ef4
268ef4
	at_store(
268ef4
		pstate,
268ef4
		0);
268ef4
268ef4
	return __ntapi->zw_terminate_thread(
268ef4
		NT_CURRENT_THREAD_HANDLE,
268ef4
		__ntapi->zw_set_event(
268ef4
			hready,0));
268ef4
}
268ef4
268ef4
static intptr_t __fastcall __ntapi_tt_fork_child(
268ef4
	void *		hresumed,
268ef4
	void *		hready)
268ef4
{
268ef4
	int32_t			status;
268ef4
	nt_thread_params	tparams;
268ef4
	nt_timeout		timeout;
268ef4
	nt_timeout		zerowait;
268ef4
	intptr_t		state;
268ef4
268ef4
	at_store(
268ef4
		&state,
268ef4
		(intptr_t)hready);
268ef4
268ef4
	__ntapi->tt_aligned_block_memset(
268ef4
		&tparams,0,sizeof(tparams));
268ef4
268ef4
	tparams.start			= __fork_thread;
268ef4
	tparams.arg			= &stat;;
268ef4
	tparams.stack_size_commit	= 0x10000;
268ef4
	tparams.stack_size_reserve	= 0x20000;
268ef4
268ef4
	status = __ntapi->tt_create_local_thread(
268ef4
		&tparams);
268ef4
268ef4
	__ntapi->zw_set_event(
268ef4
		hresumed,0);
268ef4
268ef4
	if (status)
268ef4
		__ntapi->zw_terminate_process(
268ef4
			NT_CURRENT_PROCESS_HANDLE,
268ef4
			status);
268ef4
268ef4
	if (!state) {
268ef4
		__ntapi->zw_close(hresumed);
268ef4
		__ntapi->zw_close(hready);
268ef4
		__ntapi->zw_close(tparams.hthread);
268ef4
		return 0;
268ef4
	}
268ef4
268ef4
	timeout.quad  = (-1) * 10 * 1000 * 250;
268ef4
268ef4
	status = __ntapi->zw_wait_for_single_object(
268ef4
		hready,
268ef4
		NT_SYNC_NON_ALERTABLE,
268ef4
		&timeout);
268ef4
268ef4
	if (status == NT_STATUS_SUCCESS) {
268ef4
		__ntapi->zw_close(hresumed);
268ef4
		__ntapi->zw_close(hready);
268ef4
		__ntapi->zw_close(tparams.hthread);
268ef4
		return 0;
268ef4
	}
268ef4
268ef4
	__ntapi->zw_terminate_thread(
268ef4
		tparams.hthread,
268ef4
		NT_STATUS_MORE_PROCESSING_REQUIRED);
268ef4
268ef4
	zerowait.quad = 0;
268ef4
268ef4
	status = __ntapi->zw_wait_for_single_object(
268ef4
		hready,
268ef4
		NT_SYNC_NON_ALERTABLE,
268ef4
		&zerowait);
268ef4
268ef4
	if (status == NT_STATUS_SUCCESS) {
268ef4
		__ntapi->zw_close(hresumed);
268ef4
		__ntapi->zw_close(hready);
268ef4
		__ntapi->zw_close(tparams.hthread);
268ef4
		return 0;
268ef4
	}
268ef4
268ef4
	return __ntapi->zw_terminate_process(
268ef4
		NT_CURRENT_PROCESS_HANDLE,
268ef4
		status);
268ef4
}
268ef4
268ef4
static intptr_t __fastcall __ntapi_tt_fork_parent(
268ef4
	void **		hprocess,
268ef4
	void **		hthread,
268ef4
	void *		hresumed,
268ef4
	void *		hready)
268ef4
{
268ef4
	int32_t		status;
268ef4
	nt_timeout	timeout;
268ef4
	nt_timeout	zerowait;
268ef4
	uint32_t	prev;
268ef4
268ef4
	__ntapi->zw_wait_for_single_object(
268ef4
		hresumed,
268ef4
		NT_SYNC_NON_ALERTABLE,
268ef4
		0);
268ef4
268ef4
	timeout.quad = (-1) * 10 * 1000 * 500;
268ef4
268ef4
	status = __ntapi->zw_wait_for_single_object(
268ef4
		hready,
268ef4
		NT_SYNC_NON_ALERTABLE,
268ef4
		&timeout);
268ef4
268ef4
	if (status == NT_STATUS_SUCCESS) {
268ef4
		__ntapi->zw_close(hresumed);
268ef4
		__ntapi->zw_close(hready);
268ef4
		return NT_STATUS_SUCCESS;
268ef4
	}
268ef4
268ef4
	__ntapi->zw_suspend_thread(
268ef4
		*hthread,&prev;;
268ef4
268ef4
	zerowait.quad = 0;
268ef4
268ef4
	status = __ntapi->zw_wait_for_single_object(
268ef4
		hready,
268ef4
		NT_SYNC_NON_ALERTABLE,
268ef4
		&zerowait);
268ef4
268ef4
	if (status == NT_STATUS_SUCCESS) {
268ef4
		at_locked_inc(
268ef4
			&__fork_resume_stats);
268ef4
268ef4
		__ntapi->zw_resume_thread(
268ef4
			*hthread,0);
268ef4
268ef4
		__ntapi->zw_close(hresumed);
268ef4
		__ntapi->zw_close(hready);
268ef4
		return NT_STATUS_SUCCESS;
268ef4
	}
268ef4
268ef4
	at_locked_inc(
268ef4
		&__fork_retry_stats);
268ef4
268ef4
	__ntapi->zw_terminate_process(
268ef4
		*hprocess,
268ef4
		status);
268ef4
268ef4
	__ntapi->zw_close(*hprocess);
268ef4
	__ntapi->zw_close(*hthread);
268ef4
268ef4
	return status;
268ef4
}
268ef4
268ef4
intptr_t __fastcall __ntapi_tt_fork(
268ef4
	__out	void **		hprocess,
268ef4
	__out	void **		hthread)
268ef4
{
268ef4
	int32_t			status;
268ef4
	intptr_t		pid;
268ef4
	void *			hresumed;
268ef4
	void *			hready;
268ef4
	int			i;
268ef4
268ef4
	if ((status = __ntapi->tt_create_inheritable_event(
268ef4
			&hresumed,
268ef4
			NT_NOTIFICATION_EVENT,
268ef4
			NT_EVENT_NOT_SIGNALED)))
268ef4
		return -1;
268ef4
268ef4
	if ((status = __ntapi->tt_create_inheritable_event(
268ef4
			&hready,
268ef4
			NT_NOTIFICATION_EVENT,
268ef4
			NT_EVENT_NOT_SIGNALED)))
268ef4
		return -1;
268ef4
268ef4
	for (i=0; i<32; i++) {
268ef4
		if (__ntapi->zw_create_user_process)
268ef4
			pid = __ntapi_tt_fork_v2(hprocess,hthread);
268ef4
		else
268ef4
			pid = __ntapi_tt_fork_v2(hprocess,hthread);
268ef4
268ef4
		if (pid == 0) {
268ef4
			return __ntapi_tt_fork_child(
268ef4
				hresumed,hready);
268ef4
268ef4
		} else if (pid > 0) {
268ef4
			if (!(__ntapi_tt_fork_parent(
268ef4
					hprocess,hthread,
268ef4
					hresumed,hready)))
268ef4
				return pid;
268ef4
268ef4
		} else {
268ef4
			__ntapi->zw_close(hresumed);
268ef4
			__ntapi->zw_close(hready);
268ef4
			return -1;
268ef4
		}
268ef4
	}
268ef4
268ef4
	__ntapi->zw_close(hresumed);
268ef4
	__ntapi->zw_close(hready);
268ef4
268ef4
	return -1;
268ef4
}