|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
/* ntapi: Native API core library */
|
|
|
4256e2 |
/* Copyright (C) 2013--2016 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 |
}
|