kolibrios-gitea/kernel/trunk/core/sync.inc

356 lines
7.2 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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$
RWSEM_WAITING_FOR_WRITE = 0
RWSEM_WAITING_FOR_READ = 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