Blame src/process/ntapi_tt_fork.c

268ef4
/********************************************************/
268ef4
/*  ntapi: Native API core library                      */
dde53a
/*  Copyright (C) 2013--2017  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
72fe5e
static intptr_t __fastcall __ntapi_tt_fork_finalize(
72fe5e
	void **		hprocess,
72fe5e
	void **		hthread)
72fe5e
{
72fe5e
	int32_t			status;
72fe5e
	nt_oa			oa;
72fe5e
	nt_cid			cid;
72fe5e
	ntapi_internals *	__internals;
72fe5e
72fe5e
	__internals = __ntapi_internals();
72fe5e
72fe5e
	*hprocess = 0;
72fe5e
	*hthread  = 0;
72fe5e
72fe5e
	oa.len		= sizeof(oa);
72fe5e
	oa.root_dir	= 0;
72fe5e
	oa.obj_name	= 0;
72fe5e
	oa.obj_attr	= 0;
72fe5e
	oa.sec_desc	= &__internals->seq_desc;
72fe5e
	oa.sec_qos	= &__internals->seq_qos;
72fe5e
72fe5e
	cid.process_id	= pe_get_current_process_id();
72fe5e
	cid.thread_id	= pe_get_current_thread_id();
72fe5e
72fe5e
	if ((status = __ntapi->zw_open_process(
72fe5e
			hprocess,
72fe5e
			NT_PROCESS_ALL_ACCESS,
72fe5e
			&oa,&cid)))
72fe5e
		return status;
72fe5e
72fe5e
	if ((status = __ntapi->zw_open_thread(
72fe5e
			hthread,
72fe5e
			NT_THREAD_ALL_ACCESS,
72fe5e
			&oa,&cid)))
72fe5e
		return status;
72fe5e
72fe5e
	return 0;
72fe5e
}
72fe5e
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) {
72fe5e
			__ntapi_tt_fork_child(
268ef4
				hresumed,hready);
268ef4
72fe5e
			return __ntapi_tt_fork_finalize(
72fe5e
				hprocess,hthread);
72fe5e
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
}