Blame src/sync/ntapi_tt_sync_block.c

dd89bb
/********************************************************/
dd89bb
/*  ntapi: Native API core library                      */
dde53a
/*  Copyright (C) 2013--2017  Z. Gilboa                 */
dd89bb
/*  Released under GPLv2 and GPLv3; see COPYING.NTAPI.  */
dd89bb
/********************************************************/
dd89bb
dd89bb
#include <psxtypes/psxtypes.h>
bbc71f
#include <ntapi/nt_atomic.h>
dd89bb
#include <ntapi/nt_object.h>
dd89bb
#include <ntapi/nt_sync.h>
dd89bb
#include <ntapi/ntapi.h>
dd89bb
#include "ntapi_impl.h"
dd89bb
563a1e
static void __sync_block_memset(
563a1e
	__in	nt_sync_block *	sync_block,
563a1e
	__in	intptr_t	value)
563a1e
{
563a1e
	intptr_t * sptr = sync_block->cache_line;
563a1e
563a1e
	at_store(&sptr[0x0],value);
563a1e
	at_store(&sptr[0x1],value);
563a1e
	at_store(&sptr[0x2],value);
563a1e
	at_store(&sptr[0x3],value);
563a1e
	at_store(&sptr[0x4],value);
563a1e
	at_store(&sptr[0x5],value);
563a1e
	at_store(&sptr[0x6],value);
563a1e
	at_store(&sptr[0x7],value);
563a1e
563a1e
	if (sizeof(intptr_t) == 4) {
563a1e
		at_store(&sptr[0x8],value);
563a1e
		at_store(&sptr[0x9],value);
563a1e
		at_store(&sptr[0xa],value);
563a1e
		at_store(&sptr[0xb],value);
563a1e
		at_store(&sptr[0xc],value);
563a1e
		at_store(&sptr[0xd],value);
563a1e
		at_store(&sptr[0xe],value);
563a1e
		at_store(&sptr[0xf],value);
563a1e
	}
563a1e
}
563a1e
dd89bb
void __stdcall __ntapi_tt_sync_block_init(
dd89bb
	__in	nt_sync_block *	sync_block,
dd89bb
	__in	uint32_t	flags			__optional,
dd89bb
	__in	int32_t		srvtid			__optional,
dd89bb
	__in	int32_t		default_lock_tries	__optional,
dd89bb
	__in	int64_t		default_lock_wait	__optional,
dd89bb
	__in	void *		hsignal			__optional)
dd89bb
{
563a1e
	__sync_block_memset(
563a1e
		sync_block,0);
563a1e
563a1e
	at_store_32(
563a1e
		&sync_block->lock_tries,
563a1e
		default_lock_tries
563a1e
			? default_lock_tries
563a1e
			: __NT_SYNC_BLOCK_LOCK_TRIES);
563a1e
563a1e
	at_store_64(
563a1e
		&sync_block->lock_wait.quad,
563a1e
		default_lock_wait
563a1e
			? default_lock_wait
563a1e
			: (-1));
563a1e
563a1e
	at_store_32(
563a1e
		(int32_t *)&sync_block->flags,
563a1e
		flags);
563a1e
563a1e
	at_store_32(
563a1e
		(int32_t *)&sync_block->srvtid,
563a1e
		srvtid);
563a1e
563a1e
	at_store(
563a1e
		(intptr_t *)&sync_block->hsignal,
563a1e
		(intptr_t)hsignal);
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_sync_block_lock(
dd89bb
	__in	nt_sync_block *	sync_block,
dd89bb
	__in	int32_t		lock_tries	__optional,
dd89bb
	__in	int64_t		lock_wait	__optional,
dd89bb
	__in	uint32_t *	sig_flag	__optional)
dd89bb
{
dd89bb
	int32_t		status;
dd89bb
	int32_t		tid;
dd89bb
	intptr_t	lock;
dd89bb
	void *		hwait[2];
dd89bb
	nt_timeout	timeout;
dd89bb
dd89bb
	/* validation */
dd89bb
	if (sync_block->invalid)
dd89bb
		return NT_STATUS_INVALID_HANDLE;
dd89bb
dd89bb
	/* already owned? */
bbc71f
	if ((tid = pe_get_current_thread_id()) == sync_block->tid)
bbc71f
		return NT_STATUS_SUCCESS;
dd89bb
dd89bb
	/* yield to server? */
dfc898
	if ((sync_block->flags & NT_SYNC_BLOCK_YIELD_TO_SERVER)
dfc898
			&& ((uint32_t)tid != sync_block->srvtid)) {
dd89bb
		hwait[0] = sync_block->hserver;
dd89bb
		hwait[1] = sync_block->hsignal;
dd89bb
dd89bb
		/* signal support */
dd89bb
		if (sig_flag && *sig_flag)
dd89bb
			return NT_STATUS_ALERTED;
dd89bb
dd89bb
		/* wait */
dd89bb
		status = __ntapi->zw_wait_for_multiple_objects(
bbc71f
			2,hwait,
dd89bb
			NT_WAIT_ANY,
dd89bb
			NT_SYNC_NON_ALERTABLE,
bbc71f
			0);
dd89bb
dd89bb
		/* signal support */
dd89bb
		if (sig_flag && *sig_flag)
dd89bb
			return NT_STATUS_ALERTED;
dd89bb
	}
dd89bb
dd89bb
	/* first try */
bbc71f
	lock = at_locked_cas_32(
bbc71f
		&sync_block->tid,
bbc71f
		0,tid);
bbc71f
bbc71f
	if (lock && (lock_tries == 1))
bbc71f
		return NT_STATUS_NOT_LOCKED;
dd89bb
dd89bb
	/* first-time contended case? */
dd89bb
	if (lock && !sync_block->hwait) {
bbc71f
		if ((status = __ntapi->tt_create_inheritable_event(
bbc71f
				&hwait[0],
bbc71f
				NT_NOTIFICATION_EVENT,
bbc71f
				NT_EVENT_NOT_SIGNALED)))
bbc71f
			return status;
dd89bb
dd89bb
		lock = at_locked_cas(
dd89bb
			(intptr_t *)&sync_block->hwait,
af4983
			0,(intptr_t)hwait[0]);
dd89bb
dd89bb
		if (lock)
af4983
			__ntapi->zw_close(hwait[0]);
dd89bb
dd89bb
		/* try again without a wait */
bbc71f
		lock = at_locked_cas_32(
bbc71f
			&sync_block->tid,
bbc71f
			0,tid);
dd89bb
	}
dd89bb
dd89bb
	/* contended case? */
dd89bb
	if (lock) {
dd89bb
		hwait[0] = sync_block->hwait;
dd89bb
		hwait[1] = sync_block->hsignal;
dd89bb
dd89bb
		lock_tries = lock_tries
dd89bb
			? lock_tries
dd89bb
			: sync_block->lock_tries;
dd89bb
dd89bb
		timeout.quad = lock_wait
dd89bb
			? lock_wait
dd89bb
			: sync_block->lock_wait.quad;
dd89bb
dd89bb
		for (; lock && lock_tries; lock_tries--) {
dd89bb
			/* signal support */
dd89bb
			if (sig_flag && *sig_flag)
dd89bb
				return NT_STATUS_ALERTED;
dd89bb
dd89bb
			/* wait */
dd89bb
			status = __ntapi->zw_wait_for_multiple_objects(
af4983
				2,hwait,
dd89bb
				NT_WAIT_ANY,
dd89bb
				NT_SYNC_NON_ALERTABLE,
dd89bb
				&timeout);
dd89bb
dd89bb
			/* check status */
bbc71f
			if ((status >= NT_STATUS_WAIT_0) && (status < NT_STATUS_WAIT_CAP))
bbc71f
				(void)0;
bbc71f
			else if (status == NT_STATUS_TIMEOUT)
bbc71f
				(void)0;
bbc71f
			else
dd89bb
				return status;
dd89bb
dd89bb
			/* signal support */
dd89bb
			if (sig_flag && *sig_flag)
dd89bb
				return NT_STATUS_ALERTED;
dd89bb
dd89bb
			/* try again */
bbc71f
			lock = at_locked_cas_32(
bbc71f
				&sync_block->tid,
bbc71f
				0,tid);
dd89bb
		};
dd89bb
	}
dd89bb
bbc71f
	if (lock)
bbc71f
		return NT_STATUS_NOT_LOCKED;
dd89bb
dd89bb
	/* shared section support */
563a1e
	at_store_32(
563a1e
		&sync_block->pid,
563a1e
		pe_get_current_process_id());
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_sync_block_server_lock(
dd89bb
	__in	nt_sync_block *	sync_block,
dd89bb
	__in	int32_t		lock_tries	__optional,
dd89bb
	__in	int64_t		lock_wait	__optional,
dd89bb
	__in	uint32_t *	sig_flag	__optional)
dd89bb
{
dd89bb
	int32_t status;
dd89bb
dd89bb
	/* validation */
bbc71f
	if (sync_block->invalid)
dd89bb
		return NT_STATUS_INVALID_HANDLE;
dd89bb
dd89bb
	else if (sync_block->srvtid != pe_get_current_thread_id())
dd89bb
		return NT_STATUS_RESOURCE_NOT_OWNED;
dd89bb
dd89bb
	/* try once without yield request */
dd89bb
	status = __ntapi_tt_sync_block_lock(
dd89bb
		sync_block,
bbc71f
		1,lock_wait,
dd89bb
		sig_flag);
dd89bb
dd89bb
	if (status == NT_STATUS_SUCCESS)
dd89bb
		return status;
dd89bb
dd89bb
	/* hserver */
dd89bb
	if (!sync_block->hserver) {
bbc71f
		if ((status = __ntapi->tt_create_inheritable_event(
bbc71f
				&sync_block->hserver,
bbc71f
				NT_NOTIFICATION_EVENT,
bbc71f
				NT_EVENT_NOT_SIGNALED)))
bbc71f
			return status;
dd89bb
	} else {
bbc71f
		if ((status = __ntapi->zw_reset_event(
d74580
				sync_block->hserver,0)))
bbc71f
			return status;
dd89bb
	}
dd89bb
dd89bb
	/* yield request: set */
563a1e
	at_locked_or_32(
563a1e
		(int32_t *)&sync_block->flags,
563a1e
		NT_SYNC_BLOCK_YIELD_TO_SERVER);
dd89bb
dd89bb
	/* try again */
dd89bb
	status = __ntapi_tt_sync_block_lock(
dd89bb
		sync_block,
dd89bb
		lock_tries,
dd89bb
		lock_wait,
dd89bb
		sig_flag);
dd89bb
dd89bb
	/* yield request: unset */
563a1e
	at_locked_xor_32(
563a1e
		(int32_t *)&sync_block->flags,
563a1e
		NT_SYNC_BLOCK_YIELD_TO_SERVER);
dd89bb
dd89bb
	__ntapi->zw_set_event(
dd89bb
		sync_block->hserver,
bbc71f
		0);
dd89bb
dd89bb
	/* (locking not guaranteed) */
dd89bb
	return status;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_sync_block_unlock(
dd89bb
	__in	nt_sync_block *	sync_block)
dd89bb
{
c0bd29
	union {
c0bd29
		int64_t			i64;
c0bd29
		nt_large_integer	nti64;
c0bd29
	} cmp;
dd89bb
dd89bb
	if (sync_block->invalid)
dd89bb
		return NT_STATUS_INVALID_HANDLE;
dd89bb
c0bd29
	cmp.nti64.ihigh = pe_get_current_process_id();
c0bd29
	cmp.nti64.ulow  = pe_get_current_thread_id();
dd89bb
c0bd29
	if (cmp.i64 != at_locked_cas_64(
dd89bb
			(int64_t *)&sync_block->tid,
c0bd29
			cmp.i64,0))
dd89bb
		return NT_STATUS_RESOURCE_NOT_OWNED;
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}
dd89bb
dd89bb
dd89bb
int32_t __stdcall __ntapi_tt_sync_block_discard(
dd89bb
	__in	nt_sync_block *	sync_block)
dd89bb
{
dd89bb
	if (sync_block->hwait)
bbc71f
		__ntapi->zw_close(
bbc71f
			sync_block->hwait);
dd89bb
dd89bb
	if (sync_block->hserver)
bbc71f
		__ntapi->zw_close(
bbc71f
			sync_block->hserver);
dd89bb
563a1e
	__sync_block_memset(
563a1e
		sync_block,-1);
dd89bb
dd89bb
	return NT_STATUS_SUCCESS;
dd89bb
}