kolibrios/kernel/branches/kolibri-lldw/posix/pipe.inc

340 lines
7.9 KiB
PHP
Raw Normal View History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
F_READ = 0x0001 ; file opened for reading
F_WRITE = 0x0002 ; file opened for writing
O_CLOEXEC = 0x40000
PIPE_BUFFER_SIZE = 4096
iglobal
align 4
pipe_file_ops:
dd pipe_close ;0
dd pipe_read ;1
dd pipe_write ;2
endg
;int pipe2(int pipefd[2], int flags);
;ecx pipefd
;edx flags
align 4
sys_pipe2:
.pipeflags equ esp+16
.pipefd equ esp+12
.fdread equ esp+8
.fdwrite equ esp+4
.intpipe equ esp
push ebp
test ecx, ecx
mov ebp, -EFAULT
js .fail
test edx, not O_CLOEXEC
mov ebp, -EINVAL
jnz .fail
push edx
push ecx
sub esp, (5-2)*4
mov ecx, sizeof.FILED
call create_object
mov [.fdread], eax
test eax, eax
mov ebp, -EMFILE
jz .err_0
mov ecx, sizeof.FILED
call create_object
mov [.fdwrite], eax
test eax, eax
jz .err_1
mov eax, sizeof.PIPE
call malloc
test eax, eax
mov ebp, -ENFILE
jz .err_2
mov ebp, eax
stdcall create_ring_buffer, PIPE_BUFFER_SIZE, PG_SWR
test eax, eax
jz .err_3
mov [ebp+PIPE.pipe_ops], pipe_file_ops
mov [ebp+PIPE.buffer], eax
xor eax, eax
mov [ebp+PIPE.count], eax
mov [ebp+PIPE.read_end], eax
mov [ebp+PIPE.write_end], eax
inc eax
mov [ebp+PIPE.readers], eax
mov [ebp+PIPE.writers], eax
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_init
lea ecx, [ebp+PIPE.rlist]
list_init ecx
lea ecx, [ebp+PIPE.wlist]
list_init ecx
mov eax, [.fdread]
mov edx, [.fdwrite]
mov ecx, [.pipefd]
mov [eax+FILED.magic], 'PIPE'
mov [eax+FILED.destroy], 0
mov [eax+FILED.mode], F_READ
mov [eax+FILED.file], ebp
mov [edx+FILED.magic], 'PIPE'
mov [edx+FILED.destroy], 0
mov [edx+FILED.mode], F_WRITE
mov [edx+FILED.file], ebp
mov eax, [eax+FILED.handle]
mov edx, [edx+FILED.handle]
mov [ecx], eax
mov [ecx+4], edx
add esp, 5*4
pop ebp
xor eax, eax
mov [esp+SYSCALL_STACK._eax], eax
ret
.err_3:
mov eax, ebp
call free
mov ebp, -ENFILE
.err_2:
mov ecx, [.fdwrite]
call destroy_object
.err_1:
mov ecx, [.fdread]
call destroy_object
.err_0:
add esp, 5*4
.fail:
mov eax, ebp
pop ebp
mov [esp+SYSCALL_STACK._eax], eax
ret
purge .pipeflags
purge .filefd
purge .fdread
purge .fdwrite
purge .intpipe
; edx dst_buf
; esi read count
; ebp pipe
align 4
pipe_read:
mov edi, edx
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
.again:
xor eax, eax
cmp eax, [ebp+PIPE.writers]
je .eof
mov ecx, [ebp+PIPE.count]
test ecx, ecx
jz .wait
.check_count:
cmp ecx, esi
jb .read
mov ecx, esi
.read:
mov esi, [ebp+PIPE.buffer]
add esi, [ebp+PIPE.read_end]
mov [esp+SYSCALL_STACK._eax], ecx
sub [ebp+PIPE.count], ecx
cld
rep movsb
and esi, 0xFFF
mov [ebp+PIPE.read_end], esi
lea ecx, [ebp+PIPE.wlist]
cmp ecx, [ebp+PIPE.wlist.next]
je @F
mov ecx, [ecx+MUTEX_WAITER.task]
mov [ecx+TASKDATA.state], TSTATE_RUNNING ;activate writer task
@@:
cmp [ebp+PIPE.count], 0
je @F
lea eax, [ebp+PIPE.rlist]
cmp eax, [ebp+PIPE.rlist.next]
je @F
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING ;activate reader task
@@:
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
ret
.wait:
pushfd
cli
sub esp, sizeof.MUTEX_WAITER
mov ebx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], ebx
lea edx, [ebp+PIPE.rlist]
list_add_tail esp, edx ;esp= new waiter, edx= list head
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
mov [ebx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
list_del esp
add esp, sizeof.MUTEX_WAITER
popfd
jmp .again
.eof:
mov [esp+SYSCALL_STACK._eax], eax
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
ret
; edx src_buf
; esi write count
; ebp pipe
align 4
pipe_write:
.written equ esp
push 0 ;written
mov ebx, esi ;ebx = write count
mov esi, edx ;esi = src
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
.again:
xor eax, eax
cmp eax, [ebp+PIPE.readers]
je .epipe
mov ecx, 4096
sub ecx, [ebp+PIPE.count]
jz .wait ;wait if buffer full
.check_count:
cmp ecx, ebx
jb .write
mov ecx, ebx
.write:
mov edi, [ebp+PIPE.buffer]
add edi, [ebp+PIPE.write_end]
add [.written], ecx
sub ebx, ecx
add [ebp+PIPE.count], ecx
cld
rep movsb
and edi, 0xFFF
mov [ebp+PIPE.write_end], edi
pushfd
cli
lea eax, [ebp+PIPE.rlist]
cmp eax, [ebp+PIPE.rlist.next]
je @F
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING ;activate reader task
@@:
cmp [ebp+PIPE.count], 4096
je @F
lea ecx, [ebp+PIPE.wlist]
cmp ecx, [ebp+PIPE.wlist.next]
je @F
mov ecx, [eax+MUTEX_WAITER.task]
mov [ecx+TASKDATA.state], TSTATE_RUNNING ;activate writer task
@@:
popfd
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
test ebx, ebx
jnz .again
pop eax ; written
mov [esp+SYSCALL_STACK._eax], eax
ret
.wait:
pushfd
cli
sub esp, sizeof.MUTEX_WAITER
mov ecx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], ecx
lea edx, [ebp+PIPE.wlist]
list_add_tail esp, edx ;esp= new waiter, edx= list head
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
mov [ecx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
list_del esp
add esp, sizeof.MUTEX_WAITER
popfd
jmp .again
.epipe:
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
add esp, 4
mov [esp+SYSCALL_STACK._eax], -EPIPE
ret
align 4
pipe_close:
mov [esp+SYSCALL_STACK._eax], -EBADF
ret