| |
| |
| |
| |
| |
| |
| #include <psxtypes/psxtypes.h> |
| #include <ntapi/nt_atomic.h> |
| #include <ntapi/nt_object.h> |
| #include <ntapi/nt_sync.h> |
| #include <ntapi/ntapi.h> |
| #include "ntapi_impl.h" |
| |
| static void __sync_block_memset( |
| __in nt_sync_block * sync_block, |
| __in intptr_t value) |
| { |
| intptr_t * sptr = sync_block->cache_line; |
| |
| at_store(&sptr[0x0],value); |
| at_store(&sptr[0x1],value); |
| at_store(&sptr[0x2],value); |
| at_store(&sptr[0x3],value); |
| at_store(&sptr[0x4],value); |
| at_store(&sptr[0x5],value); |
| at_store(&sptr[0x6],value); |
| at_store(&sptr[0x7],value); |
| |
| if (sizeof(intptr_t) == 4) { |
| at_store(&sptr[0x8],value); |
| at_store(&sptr[0x9],value); |
| at_store(&sptr[0xa],value); |
| at_store(&sptr[0xb],value); |
| at_store(&sptr[0xc],value); |
| at_store(&sptr[0xd],value); |
| at_store(&sptr[0xe],value); |
| at_store(&sptr[0xf],value); |
| } |
| } |
| |
| void __stdcall __ntapi_tt_sync_block_init( |
| __in nt_sync_block * sync_block, |
| __in uint32_t flags __optional, |
| __in int32_t srvtid __optional, |
| __in int32_t default_lock_tries __optional, |
| __in int64_t default_lock_wait __optional, |
| __in void * hsignal __optional) |
| { |
| __sync_block_memset( |
| sync_block,0); |
| |
| at_store_32( |
| &sync_block->lock_tries, |
| default_lock_tries |
| ? default_lock_tries |
| : __NT_SYNC_BLOCK_LOCK_TRIES); |
| |
| at_store_64( |
| &sync_block->lock_wait.quad, |
| default_lock_wait |
| ? default_lock_wait |
| : (-1)); |
| |
| at_store_32( |
| (int32_t *)&sync_block->flags, |
| flags); |
| |
| at_store_32( |
| (int32_t *)&sync_block->srvtid, |
| srvtid); |
| |
| at_store( |
| (intptr_t *)&sync_block->hsignal, |
| (intptr_t)hsignal); |
| } |
| |
| |
| int32_t __stdcall __ntapi_tt_sync_block_lock( |
| __in nt_sync_block * sync_block, |
| __in int32_t lock_tries __optional, |
| __in int64_t lock_wait __optional, |
| __in uint32_t * sig_flag __optional) |
| { |
| int32_t status; |
| int32_t tid; |
| intptr_t lock; |
| void * hwait[2]; |
| nt_timeout timeout; |
| |
| |
| if (sync_block->invalid) |
| return NT_STATUS_INVALID_HANDLE; |
| |
| |
| if ((tid = pe_get_current_thread_id()) == sync_block->tid) |
| return NT_STATUS_SUCCESS; |
| |
| |
| if ((sync_block->flags & NT_SYNC_BLOCK_YIELD_TO_SERVER) |
| && ((uint32_t)tid != sync_block->srvtid)) { |
| hwait[0] = sync_block->hserver; |
| hwait[1] = sync_block->hsignal; |
| |
| |
| if (sig_flag && *sig_flag) |
| return NT_STATUS_ALERTED; |
| |
| |
| status = __ntapi->zw_wait_for_multiple_objects( |
| 2,hwait, |
| NT_WAIT_ANY, |
| NT_SYNC_NON_ALERTABLE, |
| 0); |
| |
| |
| if (sig_flag && *sig_flag) |
| return NT_STATUS_ALERTED; |
| } |
| |
| |
| lock = at_locked_cas_32( |
| &sync_block->tid, |
| 0,tid); |
| |
| if (lock && (lock_tries == 1)) |
| return NT_STATUS_NOT_LOCKED; |
| |
| |
| if (lock && !sync_block->hwait) { |
| if ((status = __ntapi->tt_create_inheritable_event( |
| &hwait[0], |
| NT_NOTIFICATION_EVENT, |
| NT_EVENT_NOT_SIGNALED))) |
| return status; |
| |
| lock = at_locked_cas( |
| (intptr_t *)&sync_block->hwait, |
| 0,(intptr_t)hwait[0]); |
| |
| if (lock) |
| __ntapi->zw_close(hwait[0]); |
| |
| |
| lock = at_locked_cas_32( |
| &sync_block->tid, |
| 0,tid); |
| } |
| |
| |
| if (lock) { |
| hwait[0] = sync_block->hwait; |
| hwait[1] = sync_block->hsignal; |
| |
| lock_tries = lock_tries |
| ? lock_tries |
| : sync_block->lock_tries; |
| |
| timeout.quad = lock_wait |
| ? lock_wait |
| : sync_block->lock_wait.quad; |
| |
| for (; lock && lock_tries; lock_tries--) { |
| |
| if (sig_flag && *sig_flag) |
| return NT_STATUS_ALERTED; |
| |
| |
| status = __ntapi->zw_wait_for_multiple_objects( |
| 2,hwait, |
| NT_WAIT_ANY, |
| NT_SYNC_NON_ALERTABLE, |
| &timeout); |
| |
| |
| if ((status >= NT_STATUS_WAIT_0) && (status < NT_STATUS_WAIT_CAP)) |
| (void)0; |
| else if (status == NT_STATUS_TIMEOUT) |
| (void)0; |
| else |
| return status; |
| |
| |
| if (sig_flag && *sig_flag) |
| return NT_STATUS_ALERTED; |
| |
| |
| lock = at_locked_cas_32( |
| &sync_block->tid, |
| 0,tid); |
| }; |
| } |
| |
| if (lock) |
| return NT_STATUS_NOT_LOCKED; |
| |
| |
| at_store_32( |
| &sync_block->pid, |
| pe_get_current_process_id()); |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| int32_t __stdcall __ntapi_tt_sync_block_server_lock( |
| __in nt_sync_block * sync_block, |
| __in int32_t lock_tries __optional, |
| __in int64_t lock_wait __optional, |
| __in uint32_t * sig_flag __optional) |
| { |
| int32_t status; |
| |
| |
| if (sync_block->invalid) |
| return NT_STATUS_INVALID_HANDLE; |
| |
| else if (sync_block->srvtid != pe_get_current_thread_id()) |
| return NT_STATUS_RESOURCE_NOT_OWNED; |
| |
| |
| status = __ntapi_tt_sync_block_lock( |
| sync_block, |
| 1,lock_wait, |
| sig_flag); |
| |
| if (status == NT_STATUS_SUCCESS) |
| return status; |
| |
| |
| if (!sync_block->hserver) { |
| if ((status = __ntapi->tt_create_inheritable_event( |
| &sync_block->hserver, |
| NT_NOTIFICATION_EVENT, |
| NT_EVENT_NOT_SIGNALED))) |
| return status; |
| } else { |
| if ((status = __ntapi->zw_reset_event( |
| sync_block->hserver,0))) |
| return status; |
| } |
| |
| |
| at_locked_or_32( |
| (int32_t *)&sync_block->flags, |
| NT_SYNC_BLOCK_YIELD_TO_SERVER); |
| |
| |
| status = __ntapi_tt_sync_block_lock( |
| sync_block, |
| lock_tries, |
| lock_wait, |
| sig_flag); |
| |
| |
| at_locked_xor_32( |
| (int32_t *)&sync_block->flags, |
| NT_SYNC_BLOCK_YIELD_TO_SERVER); |
| |
| __ntapi->zw_set_event( |
| sync_block->hserver, |
| 0); |
| |
| |
| return status; |
| } |
| |
| |
| int32_t __stdcall __ntapi_tt_sync_block_unlock( |
| __in nt_sync_block * sync_block) |
| { |
| union { |
| int64_t i64; |
| nt_large_integer nti64; |
| } cmp; |
| |
| if (sync_block->invalid) |
| return NT_STATUS_INVALID_HANDLE; |
| |
| cmp.nti64.ihigh = pe_get_current_process_id(); |
| cmp.nti64.ulow = pe_get_current_thread_id(); |
| |
| if (cmp.i64 != at_locked_cas_64( |
| (int64_t *)&sync_block->tid, |
| cmp.i64,0)) |
| return NT_STATUS_RESOURCE_NOT_OWNED; |
| |
| return NT_STATUS_SUCCESS; |
| } |
| |
| |
| int32_t __stdcall __ntapi_tt_sync_block_discard( |
| __in nt_sync_block * sync_block) |
| { |
| if (sync_block->hwait) |
| __ntapi->zw_close( |
| sync_block->hwait); |
| |
| if (sync_block->hserver) |
| __ntapi->zw_close( |
| sync_block->hserver); |
| |
| __sync_block_memset( |
| sync_block,-1); |
| |
| return NT_STATUS_SUCCESS; |
| } |