6e1bd6d91d
git-svn-id: svn://kolibrios.org@6240 a494cfbc-eb01-0410-851d-a64ba20cac60
605 lines
13 KiB
PHP
605 lines
13 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;; Synhronization for MenuetOS. ;;
|
|
;; Author: Halyavin Andrey, halyavin@land.ru ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
$Revision$
|
|
|
|
align 4
|
|
;struct futex* __fastcall create_futex(int *ptr)
|
|
create_futex:
|
|
push ecx
|
|
mov ecx, sizeof.FUTEX
|
|
call create_object
|
|
pop ecx
|
|
test eax, eax
|
|
jz .fail
|
|
|
|
mov [eax+FUTEX.magic], 'FUTX'
|
|
mov [eax+FUTEX.destroy], 0
|
|
mov [eax+FUTEX.pointer], ecx
|
|
lea ecx, [eax+FUTEX.wait_list]
|
|
list_init ecx
|
|
mov [eax+FUTEX.flags], 0
|
|
.fail:
|
|
ret
|
|
|
|
align 4
|
|
;int __fastcall destroy_futex(struct futex *futex)
|
|
destroy_futex:
|
|
push esi
|
|
mov esi, [current_process]
|
|
mov edx, [ecx+FUTEX.handle]
|
|
|
|
pushfd
|
|
cli
|
|
|
|
lea eax, [ecx+FUTEX.wait_list]
|
|
cmp eax, [eax+LHEAD.next]
|
|
jne .fail
|
|
|
|
mov eax, [esi+PROC.ht_next]
|
|
mov [esi+PROC.htab+edx*4], eax
|
|
mov [esi+PROC.ht_next], edx
|
|
inc [esi+PROC.ht_free]
|
|
|
|
popfd
|
|
pop esi
|
|
|
|
mov eax, ecx
|
|
call free
|
|
xor eax, eax
|
|
ret
|
|
|
|
.fail:
|
|
popfd
|
|
pop esi
|
|
mov eax, -1
|
|
ret
|
|
|
|
|
|
iglobal
|
|
align 4
|
|
f77call:
|
|
dd f77.futex_init ;0
|
|
dd f77.futex_destroy ;1
|
|
dd f77.futex_wait ;2
|
|
dd f77.futex_wake ;3
|
|
.end:
|
|
endg
|
|
|
|
align 4
|
|
sys_synchronization:
|
|
f77:
|
|
test ebx, ebx
|
|
jz .futex_init
|
|
|
|
cmp ebx, (f77call.end-f77call)/4
|
|
jae .fail
|
|
|
|
cmp ecx, STDERR_FILENO
|
|
jbe .fail
|
|
cmp ecx, (PROC.pdt_0 - PROC.htab)/4
|
|
jae .fail
|
|
|
|
mov edi, [current_process]
|
|
mov ebp, [edi+PROC.htab+ecx*4]
|
|
|
|
cmp [ebp+FUTEX.magic], 'FUTX'
|
|
jne .fail
|
|
cmp [ebp+FUTEX.handle], ecx
|
|
jne .fail
|
|
|
|
jmp dword [f77call+ebx*4]
|
|
|
|
.fail:
|
|
mov [esp+SYSCALL_STACK._eax], -1
|
|
ret
|
|
|
|
align 4
|
|
.futex_init:
|
|
call create_futex
|
|
test eax, eax
|
|
jz @F
|
|
mov eax, [eax+FUTEX.handle]
|
|
@@:
|
|
mov [esp+SYSCALL_STACK._eax], eax
|
|
ret
|
|
|
|
|
|
align 4
|
|
;ecx futex handle
|
|
;edi current process
|
|
;ebp futex object
|
|
.futex_destroy:
|
|
mov ecx, ebp
|
|
call destroy_futex
|
|
mov [esp+SYSCALL_STACK._eax], eax
|
|
ret
|
|
|
|
align 4
|
|
;ecx futex handle
|
|
;edx control value
|
|
;esi timeout
|
|
;edi current process
|
|
;ebp futex object
|
|
.futex_wait:
|
|
test esi, esi
|
|
jnz .futex_wait_timeout
|
|
mov ecx, [ebp+FUTEX.pointer]
|
|
mov eax, edx
|
|
lock cmpxchg [ecx], edx
|
|
je .wait_slow
|
|
|
|
mov [esp+SYSCALL_STACK._eax], -2
|
|
ret
|
|
|
|
.wait_slow:
|
|
pushfd
|
|
cli
|
|
|
|
sub esp, sizeof.MUTEX_WAITER
|
|
mov ebx, [TASK_BASE]
|
|
mov [esp+MUTEX_WAITER.task], ebx
|
|
lea esi, [ebp+FUTEX.wait_list]
|
|
|
|
list_add_tail esp, esi ;esp= new waiter, esi= list head
|
|
mov eax, edx
|
|
.again:
|
|
mov [ebx+TASKDATA.state], 1
|
|
call change_task
|
|
|
|
lock cmpxchg [ecx], edx
|
|
je .again
|
|
|
|
list_del esp
|
|
add esp, sizeof.MUTEX_WAITER
|
|
|
|
popfd
|
|
mov [esp+SYSCALL_STACK._eax], 0
|
|
ret
|
|
|
|
align 4
|
|
;ecx futex handle
|
|
;edx control value
|
|
;esi timeout
|
|
;edi current process
|
|
;ebp futex object
|
|
|
|
.futex_wait_timeout:
|
|
mov ecx, [ebp+FUTEX.pointer]
|
|
mov eax, edx
|
|
lock cmpxchg [ecx], edx ;wait until old_value == new_value
|
|
je .wait_slow_timeout
|
|
|
|
mov [esp+SYSCALL_STACK._eax], -2
|
|
ret
|
|
|
|
align 4
|
|
.wait_test:
|
|
xor eax, eax
|
|
ret
|
|
|
|
.wait_slow_timeout:
|
|
pushfd
|
|
cli
|
|
|
|
sub esp, sizeof.MUTEX_WAITER
|
|
|
|
mov ebx, [current_slot]
|
|
mov [ebx+APPDATA.wait_test], f77.wait_test
|
|
mov [ebx+APPDATA.wait_timeout], esi
|
|
mov [ebx+APPDATA.wait_param], ebp
|
|
mov eax, [timer_ticks]
|
|
mov [ebx+APPDATA.wait_begin], eax
|
|
mov eax, [TASK_BASE]
|
|
mov [eax+TASKDATA.state], 5
|
|
|
|
mov [esp+MUTEX_WAITER.task], eax
|
|
lea esi, [ebp+FUTEX.wait_list]
|
|
|
|
list_add_tail esp, esi ;esp= new waiter, esi= list head
|
|
|
|
.again_timeout:
|
|
call change_task
|
|
mov eax, [ebx+APPDATA.wait_param]
|
|
test eax, eax
|
|
jz .timeout
|
|
|
|
mov eax, edx
|
|
lock cmpxchg [ecx], edx
|
|
jz .again_timeout
|
|
@@:
|
|
list_del esp
|
|
add esp, sizeof.MUTEX_WAITER
|
|
|
|
popfd
|
|
mov [esp+SYSCALL_STACK._eax], 0
|
|
ret
|
|
|
|
.timeout:
|
|
list_del esp
|
|
add esp, sizeof.MUTEX_WAITER
|
|
|
|
popfd
|
|
mov [esp+SYSCALL_STACK._eax], -1
|
|
ret
|
|
|
|
|
|
align 4
|
|
;ecx futex handle
|
|
;edx number of threads
|
|
;edi current process
|
|
;ebp futex object
|
|
.futex_wake:
|
|
|
|
xor ecx, ecx
|
|
|
|
pushfd
|
|
cli
|
|
|
|
lea ebx, [ebp+FUTEX.wait_list]
|
|
mov esi, [ebx+LHEAD.next]
|
|
.wake:
|
|
cmp esi, ebx
|
|
je .done
|
|
|
|
mov eax, [esi+MUTEX_WAITER.task]
|
|
mov [eax+TASKDATA.state], 0
|
|
|
|
mov esi, [esi+MUTEX_WAITER.list.next]
|
|
inc ecx
|
|
cmp ecx, edx
|
|
jb .wake
|
|
.done:
|
|
popfd
|
|
mov [esp+SYSCALL_STACK._eax], ecx
|
|
ret
|
|
|
|
RWSEM_WAITING_FOR_WRITE equ 0
|
|
RWSEM_WAITING_FOR_READ equ 1
|
|
|
|
;void __fastcall mutex_init(struct mutex *lock)
|
|
|
|
align 4
|
|
mutex_init:
|
|
mov [ecx+MUTEX.wait_list.next], ecx
|
|
mov [ecx+MUTEX.wait_list.prev], ecx
|
|
mov [ecx+MUTEX.count], 1
|
|
ret
|
|
|
|
;void __fastcall mutex_lock(struct mutex *lock)
|
|
|
|
align 4
|
|
mutex_lock:
|
|
|
|
dec [ecx+MUTEX.count]
|
|
jns .done
|
|
|
|
pushfd
|
|
cli
|
|
|
|
sub esp, sizeof.MUTEX_WAITER
|
|
|
|
list_add_tail esp, ecx ;esp= new waiter, ecx= list head
|
|
|
|
mov edx, [TASK_BASE]
|
|
mov [esp+MUTEX_WAITER.task], edx
|
|
|
|
.forever:
|
|
|
|
mov eax, -1
|
|
xchg eax, [ecx+MUTEX.count]
|
|
dec eax
|
|
jz @F
|
|
|
|
mov [edx+TASKDATA.state], 1
|
|
call change_task
|
|
jmp .forever
|
|
@@:
|
|
mov eax, ecx
|
|
list_del esp
|
|
|
|
cmp [eax+MUTEX.wait_list.next], eax
|
|
jne @F
|
|
|
|
mov [eax+MUTEX.count], 0
|
|
@@:
|
|
add esp, sizeof.MUTEX_WAITER
|
|
|
|
popfd
|
|
.done:
|
|
ret
|
|
|
|
;void __fastcall mutex_unlock(struct mutex *lock)
|
|
|
|
align 4
|
|
mutex_unlock:
|
|
|
|
pushfd
|
|
cli
|
|
|
|
mov eax, [ecx+MUTEX.wait_list.next]
|
|
cmp eax, ecx
|
|
mov [ecx+MUTEX.count], 1
|
|
je @F
|
|
|
|
mov eax, [eax+MUTEX_WAITER.task]
|
|
mov [eax+TASKDATA.state], 0
|
|
@@:
|
|
popfd
|
|
ret
|
|
|
|
|
|
;void __fastcall init_rwsem(struct rw_semaphore *sem)
|
|
|
|
align 4
|
|
init_rwsem:
|
|
mov [ecx+RWSEM.wait_list.next], ecx
|
|
mov [ecx+RWSEM.wait_list.prev], ecx
|
|
mov [ecx+RWSEM.count], 0
|
|
ret
|
|
|
|
;void __fastcall down_read(struct rw_semaphore *sem)
|
|
|
|
align 4
|
|
down_read:
|
|
pushfd
|
|
cli
|
|
|
|
mov eax, [ecx+RWSEM.count]
|
|
test eax, eax
|
|
js @F
|
|
|
|
cmp ecx, [ecx+RWSEM.wait_list.next]
|
|
je .ok
|
|
@@:
|
|
sub esp, sizeof.MUTEX_WAITER
|
|
|
|
mov eax, [TASK_BASE]
|
|
mov [esp+MUTEX_WAITER.task], eax
|
|
mov [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
|
|
mov [eax+TASKDATA.state], 1
|
|
|
|
list_add_tail esp, ecx ;esp= new waiter, ecx= list head
|
|
|
|
call change_task
|
|
|
|
add esp, sizeof.MUTEX_WAITER
|
|
popfd
|
|
ret
|
|
.ok:
|
|
inc eax
|
|
mov [ecx+RWSEM.count], eax
|
|
|
|
popfd
|
|
ret
|
|
|
|
;void __fastcall down_write(struct rw_semaphore *sem)
|
|
|
|
align 4
|
|
down_write:
|
|
pushfd
|
|
cli
|
|
sub esp, sizeof.MUTEX_WAITER
|
|
|
|
mov edx, [TASK_BASE]
|
|
mov [esp+MUTEX_WAITER.task], edx
|
|
mov [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
|
|
mov [edx+TASKDATA.state], 1
|
|
|
|
list_add_tail esp, ecx ;esp= new waiter, ecx= list head
|
|
|
|
xor eax, eax
|
|
not eax
|
|
|
|
.forever:
|
|
test eax, [ecx+RWSEM.count]
|
|
jz @F
|
|
|
|
mov [edx+TASKDATA.state], 1
|
|
call change_task
|
|
jmp .forever
|
|
@@:
|
|
mov [ecx+RWSEM.count], eax
|
|
list_del esp
|
|
|
|
add esp, sizeof.MUTEX_WAITER
|
|
popfd
|
|
ret
|
|
|
|
;void __fastcall up_read(struct rw_semaphore *sem)
|
|
|
|
align 4
|
|
up_read:
|
|
pushfd
|
|
cli
|
|
|
|
dec [ecx+RWSEM.count]
|
|
jnz @F
|
|
|
|
mov eax, [ecx+RWSEM.wait_list.next]
|
|
cmp eax, ecx
|
|
je @F
|
|
|
|
mov eax, [eax+MUTEX_WAITER.task]
|
|
mov [eax+TASKDATA.state], 0
|
|
@@:
|
|
popfd
|
|
ret
|
|
|
|
;void __fastcall up_write(struct rw_semaphore *sem)
|
|
|
|
align 4
|
|
up_write:
|
|
|
|
pushfd
|
|
cli
|
|
|
|
mov eax, [ecx+RWSEM.wait_list.next]
|
|
mov [ecx+RWSEM.count], 0
|
|
|
|
cmp ecx, eax
|
|
je .done
|
|
|
|
mov edx, [eax+MUTEX_WAITER.type]
|
|
test edx, edx
|
|
jnz .wake
|
|
|
|
mov eax, [eax+MUTEX_WAITER.task]
|
|
mov [eax+TASKDATA.state], 0
|
|
.done:
|
|
popfd
|
|
ret
|
|
|
|
.wake:
|
|
push ebx
|
|
push esi
|
|
push edi
|
|
|
|
xor esi, esi
|
|
mov edi, ecx
|
|
|
|
.wake_list:
|
|
|
|
mov ebx, [eax+MUTEX_WAITER.list.next]
|
|
list_del eax
|
|
mov edx, [eax+MUTEX_WAITER.task]
|
|
mov [edx+TASKDATA.state], 0
|
|
inc esi
|
|
cmp edi, ebx
|
|
je .wake_done
|
|
|
|
mov ecx, [ebx+MUTEX_WAITER.type]
|
|
test ecx, ecx
|
|
jz .wake_done
|
|
|
|
mov eax, ebx
|
|
jmp .wake_list
|
|
|
|
.wake_done:
|
|
add [edi+RWSEM.count], esi
|
|
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
popfd
|
|
ret
|
|
|
|
|
|
purge RWSEM_WAITING_FOR_WRITE
|
|
purge RWSEM_WAITING_FOR_READ
|
|
|
|
|
|
if ~defined sync_inc
|
|
sync_inc_fix:
|
|
sync_inc fix sync_inc_fix
|
|
|
|
;simplest mutex.
|
|
macro SimpleMutex name
|
|
{
|
|
; iglobal
|
|
name dd 0
|
|
name#.type = 1
|
|
; endg
|
|
}
|
|
macro WaitSimpleMutex name
|
|
{
|
|
local start_wait,ok
|
|
start_wait=$
|
|
cli
|
|
cmp [name], dword 0
|
|
jz ok
|
|
sti
|
|
call change_task
|
|
jmp start_wait
|
|
ok=$
|
|
push eax
|
|
mov eax, dword [TASK_BASE+second_base_address]
|
|
mov eax, [eax+TASKDATA.pid]
|
|
mov [name], eax
|
|
pop eax
|
|
sti
|
|
}
|
|
macro ReleaseSimpleMutex name
|
|
{
|
|
mov [name], dword 0
|
|
}
|
|
macro TryWaitSimpleMutex name ;result in eax and in flags
|
|
{
|
|
local ok,try_end
|
|
cmp [name], dword 0
|
|
jz ok
|
|
xor eax, eax
|
|
jmp try_end
|
|
ok=$
|
|
xor eax, eax
|
|
inc eax
|
|
try_end=$
|
|
}
|
|
macro SimpleCriticalSection name
|
|
{
|
|
; iglobal
|
|
name dd 0
|
|
dd 0
|
|
name#.type=2
|
|
; endg
|
|
}
|
|
macro WaitSimpleCriticalSection name
|
|
{
|
|
local start_wait,first_wait,inc_counter,end_wait
|
|
push eax
|
|
mov eax, [TASK_BASE+second_base_address]
|
|
mov eax, [eax+TASKDATA.pid]
|
|
start_wait=$
|
|
cli
|
|
cmp [name], dword 0
|
|
jz first_wait
|
|
cmp [name], eax
|
|
jz inc_counter
|
|
sti
|
|
call change_task
|
|
jmp start_wait
|
|
first_wait=$
|
|
mov [name], eax
|
|
mov [name+4], dword 1
|
|
jmp end_wait
|
|
inc_counter=$
|
|
inc dword [name+4]
|
|
end_wait=$
|
|
sti
|
|
pop eax
|
|
}
|
|
macro ReleaseSimpleCriticalSection name
|
|
{
|
|
local release_end
|
|
dec dword [name+4]
|
|
jnz release_end
|
|
mov [name], dword 0
|
|
release_end=$
|
|
}
|
|
macro TryWaitSimpleCriticalSection name ;result in eax and in flags
|
|
{
|
|
local ok,try_end
|
|
mov eax, [CURRENT_TASK+second_base_address]
|
|
mov eax, [eax+TASKDATA.pid]
|
|
cmp [name], eax
|
|
jz ok
|
|
cmp [name], 0
|
|
jz ok
|
|
xor eax, eax
|
|
jmp try_end
|
|
ok=$
|
|
xor eax, eax
|
|
inc eax
|
|
try_end=$
|
|
}
|
|
_cli equ call MEM_HeapLock
|
|
_sti equ call MEM_HeapUnLock
|
|
end if
|
|
|