kolibrios-gitea/kernel/trunk/core/sched.inc
Sergey Semyonov (Serge) 2e1f635004 linux-like kernel mutexes
git-svn-id: svn://kolibrios.org@1434 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-03-17 17:42:57 +00:00

413 lines
10 KiB
PHP
Raw Blame History

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;;
;; Distributed under terms of the GNU General Public License ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 32
irq0:
pushad
Mov ds, ax, app_data
mov es, ax
inc [timer_ticks]
mov eax, [timer_ticks]
call playNote ; <<<--- Speaker driver
sub eax,[next_usage_update]
cmp eax,100
jb .nocounter
add [next_usage_update],100
call updatecputimes
.nocounter:
mov al,0x20 ; send End Of Interrupt signal
out 0x20,al
btr dword[DONT_SWITCH], 0
jc .return
call find_next_task
jz .return ; if there is only one running process
call do_change_task
.return:
popad
iretd
align 4
change_task:
pushfd
cli
pushad
if 0
; \begin{Mario79} ; <- must be refractoried, if used...
cmp [dma_task_switched], 1
jne .find_next_task
mov [dma_task_switched], 0
mov ebx, [dma_process]
cmp [CURRENT_TASK], ebx
je .return
mov edi, [dma_slot_ptr]
mov [CURRENT_TASK], ebx
mov [TASK_BASE], edi
jmp @f
.find_next_task:
; \end{Mario79}
end if
call find_next_task
jz .return ; the same task -> skip switch
@@: mov byte[DONT_SWITCH], 1
call do_change_task
.return:
popad
popfd
ret
uglobal
align 4
; far_jump:
; .offs dd ?
; .sel dw ?
context_counter dd 0 ;noname & halyavin
next_usage_update dd 0
timer_ticks dd 0
; prev_slot dd ?
; event_sched dd ?
endg
align 4
update_counters:
mov edi, [TASK_BASE]
rdtsc
sub eax, [edi+TASKDATA.counter_add] ; time stamp counter add
add [edi+TASKDATA.counter_sum], eax ; counter sum
ret
align 4
updatecputimes:
xor eax,eax
xchg eax,[idleuse]
mov [idleusesec],eax
mov ecx, [TASK_COUNT]
mov edi, TASK_DATA
.newupdate:
xor eax,eax
xchg eax,[edi+TASKDATA.counter_sum]
mov [edi+TASKDATA.cpu_usage],eax
add edi,0x20
loop .newupdate
ret
align 4
find_next_task:
;info:
; Find next task to execute
;retval:
; ebx = address of the APPDATA for the selected task (slot-base)
; esi = previous slot-base ([current_slot] at the begin)
; edi = address of the TASKDATA for the selected task
; ZF = 1 if the task is the same
;warning:
; [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
; [current_slot] is not set to new value (ebx)!!!
;scratched: eax,ecx
call update_counters ; edi := [TASK_BASE]
Mov esi, ebx, [current_slot]
.loop:
cmp bh,[TASK_COUNT]
jb @f
xor bh, bh
mov edi,CURRENT_TASK
@@: inc bh ; ebx += APPDATA.size
add edi,0x20 ; edi += TASKDATA.size
mov al, [edi+TASKDATA.state]
test al, al
jz .found ; state == 0
cmp al, 5
jne .loop ; state == 1,2,3,4,9
; state == 5
pushad ; more freedom for [APPDATA.wait_test]
call [ebx+APPDATA.wait_test]
mov [esp+28],eax
popad
or eax,eax
jnz @f
; testing for timeout
mov ecx, [timer_ticks]
sub ecx, [ebx+APPDATA.wait_begin]
cmp ecx, [ebx+APPDATA.wait_timeout]
jb .loop
@@: mov [ebx+APPDATA.wait_param], eax ; retval for wait
mov [edi+TASKDATA.state], 0
.found:
mov [CURRENT_TASK],bh
mov [TASK_BASE],edi
rdtsc ;call _rdtsc
mov [edi+TASKDATA.counter_add],eax ; for next using update_counters
cmp ebx, esi ;esi - previous slot-base
ret
;TODO: <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> do_change_task <EFBFBD><EFBFBD> V86...
; <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> TASKDATA.counter_add/sum <EFBFBD> do_change_task
align 4
do_change_task:
;param:
; ebx = address of the APPDATA for incoming task (new)
;warning:
; [CURRENT_TASK] and [TASK_BASE] must be changed before (e.g. in find_next_task)
; [current_slot] is the outcoming (old), and set here to a new value (ebx)
;scratched: eax,ecx,esi
mov esi,ebx
xchg esi,[current_slot]
; set new stack after saving old
mov [esi+APPDATA.saved_esp], esp
mov esp, [ebx+APPDATA.saved_esp]
; set new thread io-map
Mov dword [page_tabs+((tss._io_map_0 and -4096) shr 10)],eax,[ebx+APPDATA.io_map]
Mov dword [page_tabs+((tss._io_map_1 and -4096) shr 10)],eax,[ebx+APPDATA.io_map+4]
; set new thread memory-map
mov ecx, APPDATA.dir_table
mov eax, [ebx+ecx] ;offset>0x7F
cmp eax, [esi+ecx] ;offset>0x7F
je @f
mov cr3, eax
@@:
; set tss.esp0
Mov [tss._esp0],eax,[ebx+APPDATA.saved_esp0]
mov edx, [ebx+APPDATA.tls_base]
cmp edx, [esi+APPDATA.tls_base]
je @f
mov [tls_data_l+2],dx
shr edx,16
mov [tls_data_l+4],dl
mov [tls_data_l+7],dh
mov dx, app_tls
mov fs, dx
@@:
; set gs selector unconditionally
Mov gs,ax,graph_data
; set CR0.TS
cmp bh, byte[fpu_owner] ;bh == incoming task (new)
clts ;clear a task switch flag
je @f
mov eax, cr0 ;and set it again if the owner
or eax, CR0_TS ;of a fpu has changed
mov cr0, eax
@@: ; set context_counter (only for user pleasure ???)
inc [context_counter] ;noname & halyavin
; set debug-registers, if it's necessary
test byte[ebx+APPDATA.dbg_state], 1
jz @f
xor eax, eax
mov dr6, eax
lea esi,[ebx+ecx+APPDATA.dbg_regs-APPDATA.dir_table] ;offset>0x7F
cld
macro lodsReg [reg] {
lodsd
mov reg,eax
} lodsReg dr0, dr1, dr2, dr3, dr7
purge lodsReg
@@: ret
;end.
struc MUTEX_WAITER
{
.next rd 1
.prev rd 1
.task rd 1
.sizeof:
};
virtual at 0
MUTEX_WAITER MUTEX_WAITER
end virtual
;void __fastcall mutex_init(struct mutex *lock)
align 4
mutex_init:
lea eax, [ecx+MUTEX.next]
mov [ecx+MUTEX.count],1
mov [ecx+MUTEX.next], eax
mov [ecx+MUTEX.prev], eax
ret
;void __fastcall mutex_lock(struct mutex *lock)
align 4
mutex_lock:
dec [ecx+MUTEX.count]
jns .done
pushfd
cli
push esi
sub esp, MUTEX_WAITER.sizeof
mov eax, [ecx+MUTEX.prev]
lea esi, [ecx+MUTEX.next]
mov [ecx+MUTEX.prev], esp
mov [esp+MUTEX_WAITER.next], esi
mov [esp+MUTEX_WAITER.prev], eax
mov [eax], esp
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 edx, [esp+MUTEX_WAITER.next]
mov eax, [esp+MUTEX_WAITER.prev]
mov [eax+MUTEX_WAITER.next], edx
cmp [ecx+MUTEX.next], esi
mov [edx+MUTEX_WAITER.prev], eax
jne @F
mov [ecx+MUTEX.count], 0
@@:
add esp, MUTEX_WAITER.sizeof
pop esi
popfd
.done:
ret
;void __fastcall mutex_unlock(struct mutex *lock)
align 4
mutex_unlock:
pushfd
cli
lea eax, [ecx+MUTEX.next]
cmp eax, [ecx+MUTEX.next]
mov [ecx+MUTEX.count], 1
je @F
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], 0
@@:
popfd
ret
purge MUTEX_WAITER
if 0
struc TIMER
{
.next dd ?
.exp_time dd ?
.func dd ?
.arg dd ?
}
MAX_PROIRITY 0 ; highest, used for kernel tasks
MAX_USER_PRIORITY 0 ; highest priority for user processes
USER_PRIORITY 7 ; default (should correspond to nice 0)
MIN_USER_PRIORITY 14 ; minimum priority for user processes
IDLE_PRIORITY 15 ; lowest, only IDLE process goes here
NR_SCHED_QUEUES 16 ; MUST equal IDLE_PRIORYTY + 1
uglobal
rdy_head rd 16
endg
align 4
pick_task:
xor eax, eax
.pick:
mov ebx, [rdy_head+eax*4]
test ebx, ebx
jz .next
mov [next_task], ebx
test [ebx+flags.billable]
jz @F
mov [bill_task], ebx
@@:
ret
.next:
inc eax
jmp .pick
; param
; eax= task
;
; retval
; eax= task
; ebx= queue
; ecx= front if 1 or back if 0
align 4
shed:
cmp [eax+.tics_left], 0 ;signed compare
mov ebx, [eax+.priority]
setg ecx
jg @F
mov edx, [eax+.tics_quantum]
mov [eax+.ticks_left], edx
cmp ebx, (IDLE_PRIORITY-1)
je @F
inc ebx
@@:
ret
; param
; eax= task
align 4
enqueue:
call shed ;eax
cmp [rdy_head+ebx*4],0
jnz @F
mov [rdy_head+ebx*4], eax
mov [rdy_tail+ebx*4], eax
mov [eax+.next_ready], 0
jmp .pick
@@:
test ecx, ecx
jz .back
mov ecx, [rdy_head+ebx*4]
mov [eax+.next_ready], ecx
mov [rdy_head+ebx*4], eax
jmp .pick
.back:
mov ecx, [rdy_tail+ebx*4]
mov [ecx+.next_ready], eax
mov [rdy_tail+ebx*4], eax
mov [eax+.next_ready], 0
.pick:
call pick_proc ;select next task
ret
end if