|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
/* ntapi: Native API core library */
|
|
|
dd89bb |
/* Copyright (C) 2013,2014,2015 Z. Gilboa */
|
|
|
dd89bb |
/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */
|
|
|
dd89bb |
/********************************************************/
|
|
|
dd89bb |
|
|
|
dd89bb |
#include <psxtypes/psxtypes.h>
|
|
|
dd89bb |
#include <ntapi/nt_object.h>
|
|
|
dd89bb |
#include <ntapi/nt_sync.h>
|
|
|
dd89bb |
#include <ntapi/nt_atomic.h>
|
|
|
dd89bb |
#include <ntapi/ntapi.h>
|
|
|
dd89bb |
#include "ntapi_impl.h"
|
|
|
dd89bb |
|
|
|
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 |
{
|
|
|
dd89bb |
__ntapi->tt_aligned_block_memset(
|
|
|
dd89bb |
sync_block,
|
|
|
dd89bb |
0,sizeof(*sync_block));
|
|
|
dd89bb |
|
|
|
dd89bb |
sync_block->lock_tries = default_lock_tries
|
|
|
dd89bb |
? default_lock_tries
|
|
|
dd89bb |
: __NT_SYNC_BLOCK_LOCK_TRIES;
|
|
|
dd89bb |
|
|
|
dd89bb |
sync_block->lock_wait.quad = default_lock_wait
|
|
|
dd89bb |
? default_lock_wait
|
|
|
dd89bb |
: (-1);
|
|
|
dd89bb |
|
|
|
dd89bb |
sync_block->flags = flags;
|
|
|
dd89bb |
sync_block->srvtid = srvtid;
|
|
|
dd89bb |
sync_block->hsignal = hsignal;
|
|
|
dd89bb |
|
|
|
dd89bb |
return;
|
|
|
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? */
|
|
|
dd89bb |
tid = pe_get_current_thread_id();
|
|
|
dd89bb |
if (sync_block->tid == tid) return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* yield to server? */
|
|
|
dd89bb |
if ((sync_block->flags & NT_SYNC_BLOCK_YIELD_TO_SERVER) && (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(
|
|
|
dd89bb |
2,
|
|
|
dd89bb |
hwait,
|
|
|
dd89bb |
NT_WAIT_ANY,
|
|
|
dd89bb |
NT_SYNC_NON_ALERTABLE,
|
|
|
dd89bb |
(nt_timeout *)0);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* signal support */
|
|
|
dd89bb |
if (sig_flag && *sig_flag)
|
|
|
dd89bb |
return NT_STATUS_ALERTED;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* first try */
|
|
|
dd89bb |
lock = at_locked_cas_32(&sync_block->tid,0,tid);
|
|
|
dd89bb |
if (lock && !--lock_tries) return NT_STATUS_NOT_LOCKED;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* first-time contended case? */
|
|
|
dd89bb |
if (lock && !sync_block->hwait) {
|
|
|
dd89bb |
status = __ntapi->tt_create_inheritable_event(
|
|
|
dd89bb |
&hwait[0],
|
|
|
dd89bb |
NT_NOTIFICATION_EVENT,
|
|
|
dd89bb |
NT_EVENT_NOT_SIGNALED);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
lock = at_locked_cas(
|
|
|
dd89bb |
(intptr_t *)&sync_block->hwait,
|
|
|
dd89bb |
0,(intptr_t)hwait);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (lock)
|
|
|
dd89bb |
__ntapi->zw_close(hwait);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try again without a wait */
|
|
|
dd89bb |
lock = at_locked_cas_32(&sync_block->tid,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(
|
|
|
dd89bb |
2,
|
|
|
dd89bb |
&sync_block->hwait,
|
|
|
dd89bb |
NT_WAIT_ANY,
|
|
|
dd89bb |
NT_SYNC_NON_ALERTABLE,
|
|
|
dd89bb |
&timeout);
|
|
|
dd89bb |
|
|
|
dd89bb |
/* check status */
|
|
|
dd89bb |
if ((status != NT_STATUS_TIMEOUT) && ((uint32_t)status >= NT_STATUS_WAIT_CAP))
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* signal support */
|
|
|
dd89bb |
if (sig_flag && *sig_flag)
|
|
|
dd89bb |
return NT_STATUS_ALERTED;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* try again */
|
|
|
dd89bb |
lock = at_locked_cas_32(&sync_block->tid,0,tid);
|
|
|
dd89bb |
};
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
if (lock) return NT_STATUS_NOT_LOCKED;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* shared section support */
|
|
|
dd89bb |
sync_block->pid = 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 */
|
|
|
dd89bb |
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,
|
|
|
dd89bb |
1,
|
|
|
dd89bb |
lock_wait,
|
|
|
dd89bb |
sig_flag);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status == NT_STATUS_SUCCESS)
|
|
|
dd89bb |
return status;
|
|
|
dd89bb |
|
|
|
dd89bb |
/* hserver */
|
|
|
dd89bb |
if (!sync_block->hserver) {
|
|
|
dd89bb |
status = __ntapi->tt_create_inheritable_event(
|
|
|
dd89bb |
&sync_block->hserver,
|
|
|
dd89bb |
NT_NOTIFICATION_EVENT,
|
|
|
dd89bb |
NT_EVENT_NOT_SIGNALED);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
} else {
|
|
|
dd89bb |
status = __ntapi->zw_reset_event(
|
|
|
dd89bb |
&sync_block->hserver,
|
|
|
dd89bb |
(int32_t *)0);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (status) return status;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
/* yield request: set */
|
|
|
dd89bb |
sync_block->flags |= 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 */
|
|
|
dd89bb |
sync_block->flags ^= NT_SYNC_BLOCK_YIELD_TO_SERVER;
|
|
|
dd89bb |
|
|
|
dd89bb |
__ntapi->zw_set_event(
|
|
|
dd89bb |
sync_block->hserver,
|
|
|
dd89bb |
(int32_t *)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 |
void __stdcall __ntapi_tt_sync_block_validate(
|
|
|
dd89bb |
__in nt_sync_block * sync_block)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
at_store_32(&sync_block->invalid,0);
|
|
|
dd89bb |
|
|
|
dd89bb |
return;
|
|
|
dd89bb |
}
|
|
|
dd89bb |
|
|
|
dd89bb |
|
|
|
dd89bb |
int32_t __stdcall __ntapi_tt_sync_block_invalidate(
|
|
|
dd89bb |
__in nt_sync_block * sync_block)
|
|
|
dd89bb |
{
|
|
|
dd89bb |
int32_t invalid;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (!sync_block)
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER;
|
|
|
dd89bb |
|
|
|
dd89bb |
invalid = at_locked_cas_32(
|
|
|
dd89bb |
&sync_block->invalid,
|
|
|
dd89bb |
0,
|
|
|
dd89bb |
1);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (invalid)
|
|
|
dd89bb |
return NT_STATUS_INVALID_HANDLE;
|
|
|
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)
|
|
|
dd89bb |
return NT_STATUS_INVALID_PARAMETER;
|
|
|
dd89bb |
|
|
|
dd89bb |
if (sync_block->hwait)
|
|
|
dd89bb |
__ntapi->zw_close(sync_block->hwait);
|
|
|
dd89bb |
|
|
|
dd89bb |
if (sync_block->hserver)
|
|
|
dd89bb |
__ntapi->zw_close(sync_block->hserver);
|
|
|
dd89bb |
|
|
|
dd89bb |
__ntapi->tt_aligned_block_memset(sync_block,-1,sizeof(*sync_block));
|
|
|
dd89bb |
|
|
|
dd89bb |
return NT_STATUS_SUCCESS;
|
|
|
dd89bb |
}
|