9,491 → 9,7 |
|
$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 ;wait until old_value == new_value |
jz .wait_slow |
|
mov [esp+SYSCALL_STACK._eax], 0 |
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 |
|
.again: |
mov [ebx+TASKDATA.state], 1 |
call change_task |
|
lock cmpxchg [ecx], edx |
jz .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 |
jz .wait_slow_timeout |
|
mov [esp+SYSCALL_STACK._eax], 0 |
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 |
|
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 |