home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
DOOG
/
CTASK.ZIP
/
TSKQUE.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-12-20
|
8KB
|
320 lines
;
; --- Version 2.0 89-12-14 17:44 ---
;
; CTask - Queue management
;
; Public Domain Software written by
; Thomas Wagner
; Patschkauer Weg 31
; D-1000 Berlin 33
; West Germany
;
; Since managing the queues is one of the most timing critical
; parts of CTask, the main routines have been coded in Assembler.
; The corresponding C code is included as a reference.
;
; This file is new with 2.0.
;
name tskque
.model large,c
;
public tsk_enqueue
public tsk_dequeue
public tsk_putqueue
public tsk_enqtimer
public tsk_deqtimer
;
include tsk.mac
;
extrn tsk_dgroup: word
;
.tsk_data
;
IF SINGLE_DATA
extrn tsk_glob_rec: byte
ELSE
extrn tsk_global: dword
ENDIF
;
.tsk_edata
.tsk_code
;
extrn tsk_scheduler: far
;
;
; tsk_enqueue
;
; This routine adds a task (or any other queue element) to a queue
; in priority order. The search starts at the queue's tail end so
; as to better support the 'yield' operation (which disturbs the
; priority order in the queue).
;
;void near tsk_enqueue (queheadptr q, queptr elem)
;{
; queptr curr;
;
; while (1)
; {
; curr = q->prev;
; while (curr->kind &&
; curr->el.pri.prior < elem->el.pri.prior)
; curr = curr->prev;
; }
; elem->prev = curr;
; elem->next = curr->next;
; curr->next = elem->next->prev = elem;
;}
;
tsk_enqueue proc near uses ds di, que: far ptr, elem: far ptr
;
les di,elem
lds bx,que
mov cx,es:q_el.q_prior[di] ; load priority into BX
lds bx,q_prev[bx] ; last queue element
;
enq_loop:
cmp q_kind[bx],0 ; at head?
je enq_found ; then insert
cmp q_el.q_prior[bx],cx ; else check priority
jae enq_found ; if above or equal, insert
;
lds bx,q_prev[bx] ; backup one element
jmp enq_loop ; and try again
;
enq_found:
mov word ptr es:q_prev[di],bx ; elem->prev = curr
mov word ptr es:q_prev+2[di],ds
mov ax,word ptr q_next[bx] ; elem->next = curr->next;
mov word ptr es:q_next[di],ax
mov dx,word ptr q_next+2[bx]
mov word ptr es:q_next+2[di],dx
mov word ptr q_next[bx],di ; curr->next = elem;
mov word ptr q_next+2[bx],es
mov bx,ax
mov ds,dx
mov word ptr q_prev[bx],di ; elem->next->prev = elem
mov word ptr q_prev+2[bx],es
ret
;
tsk_enqueue endp
;
;
; tsk_putqueue
;
; This routine adds a queue element to the end of a queue.
;
;void near tsk_putqueue (queheadptr q, queptr elem)
;{
; elem->next = q;
; elem->prev = q->prev;
; q->prev = elem->prev->next = elem;
;}
;
tsk_putqueue proc near uses ds di, que: far ptr, elem: far ptr
;
les di,elem
lds bx,que
mov word ptr es:q_next[di],bx ; elem->next = que
mov word ptr es:q_next+2[di],ds
mov ax,word ptr q_prev[bx] ; elem->prev = que->prev;
mov word ptr es:q_prev[di],ax
mov dx,word ptr q_prev+2[bx]
mov word ptr es:q_prev+2[di],dx
mov word ptr q_prev[bx],di ; que->prev = elem;
mov word ptr q_prev+2[bx],es
mov bx,ax
mov ds,dx
mov word ptr q_next[bx],di ; elem->prev->next = elem
mov word ptr q_next+2[bx],es
ret
;
tsk_putqueue endp
;
;
;
; tsk_enqtimer
;
; This routine adds a task (or any other queue element) to
; the timeout queue.
;
; This is slightly different from the normal enqueue in that
; queue elements are not inserted based on priority, but rather
; based on the tick count. Each element's tick counter stores
; the difference in ticks to the previous element. This speeds
; up the timeout loop, since only the first element has to be
; counted down, but it makes insertion a tad more complicated.
;
;void near tsk_enqtimer (queptr elem, dword ticks)
;{
; queptr curr, q;
;
; if (!ticks)
; return;
; q = &GLOBDATA timer_queue;
;
; curr = q->next;
; while (curr->kind &&
; curr->el.ticks <= ticks)
; {
; ticks -= curr->el.ticks;
; curr = curr->next;
; if (!ticks)
; break;
; }
; if (curr->kind)
; curr->el.ticks -= ticks;
; elem->next = curr;
; elem->prev = curr->prev;
; curr->prev = elem->prev->next = elem;
; elem->el.ticks = ticks;
;}
;
tsk_enqtimer proc near uses ds di, elem: far ptr, ticks: dword
;
les di,elem
mov ds,cs:tsk_dgroup
IF SINGLE_DATA
lea bx,tsk_glob_rec.timer_queue
ELSE
lds bx,tsk_global
add bx,timer_queue
ENDIF
;
mov ax,word ptr (ticks) ; load tick count into DX:AX
mov dx,word ptr (ticks+2)
mov cx,ax
or cx,dx
jz enqt_ret
lds bx,q_first[bx] ; first queue element
;
et_loop:
cmp q_kind[bx],0 ; at head?
je et_found1 ; then insert
sub ax,word ptr q_el.q_ticks[bx] ; else check ticks
sbb dx,word ptr q_el.q_ticks+2[bx]
jc et_found ; insert on overflow
;
lds bx,q_next[bx] ; next element
jmp et_loop ; and try again
;
et_found:
add ax,word ptr q_el.q_ticks[bx] ; restore ticks
adc dx,word ptr q_el.q_ticks+2[bx]
;
et_found1:
mov word ptr es:q_el.q_ticks[di],ax ; elem->el.ticks = ticks
mov word ptr es:q_el.q_ticks+2[di],dx
;
cmp q_kind[bx],0 ; at head?
je et_notick ; no tick mod if yes
;
sub word ptr q_el.q_ticks[bx],ax ; else curr->el.ticks -= ticks
sbb word ptr q_el.q_ticks+2[bx],dx
;
et_notick:
mov word ptr es:q_next[di],bx ; elem->next = curr
mov word ptr es:q_next+2[di],ds
mov ax,word ptr q_prev[bx] ; elem->prev = curr->prev;
mov word ptr es:q_prev[di],ax
mov dx,word ptr q_prev+2[bx]
mov word ptr es:q_prev+2[di],dx
mov word ptr q_prev[bx],di ; curr->prev = elem;
mov word ptr q_prev+2[bx],es
mov bx,ax
mov ds,dx
mov word ptr q_next[bx],di ; elem->prev->next = elem
mov word ptr q_next+2[bx],es
;
enqt_ret:
ret
;
tsk_enqtimer endp
;
;
; tsk_dequeue
;
; This routine removes an element from a queue.
;
;void near tsk_dequeue (queptr elem)
;{
; if (elem->next == NULL)
; return;
; elem->next->prev = elem->prev;
; elem->prev->next = elem->next;
; elem->next = NULL;
;}
;
tsk_dequeue proc near uses ds di, elem: far ptr
;
lds bx,elem
les di,q_next[bx] ; remove from queue
mov ax,es ; check if enqueued
or ax,di
jz deq_ret ; nothing to do if not in queue
xor ax,ax ; clear next pointer
mov word ptr q_next[bx],ax
mov word ptr q_next+2[bx],ax
lds bx,q_prev[bx]
mov word ptr es:q_prev[di],bx
mov word ptr es:q_prev+2[di],ds
mov word ptr q_next[bx],di
mov word ptr q_next+2[bx],es
;
deq_ret:
ret
;
tsk_dequeue endp
;
;
; tsk_deqtimer
;
; This routine removes an element from the timer queue.
; It is different from the normal dequeue in that the tick
; difference must be updated for the next in line.
;
;void near tsk_deqtimer (queptr elem)
;{
; if (elem->next == NULL)
; return;
;
; if (elem->next->kind)
; elem->next->el.ticks += elem->el.ticks;
; elem->next->prev = elem->prev;
; elem->prev->next = elem->next;
; elem->next = NULL;
;}
;
tsk_deqtimer proc near uses ds di, elem: far ptr
;
lds bx,elem
les di,q_next[bx]
mov ax,es
or ax,di
jz deqtim_ret ; nothing to do if not in queue
cmp es:q_kind[di],0
je dqt_notick
mov ax,word ptr q_el.q_ticks[bx] ; first update next tick count
mov dx,word ptr q_el.q_ticks+2[bx]
add word ptr es:q_el.q_ticks[di],ax
adc word ptr es:q_el.q_ticks+2[di],dx
;
dqt_notick:
xor ax,ax
mov word ptr q_next[bx],ax
mov word ptr q_next+2[bx],ax
lds bx,q_prev[bx]
mov word ptr es:q_prev[di],bx
mov word ptr es:q_prev+2[di],ds
mov word ptr q_next[bx],di
mov word ptr q_next+2[bx],es
;
deqtim_ret:
ret
;
tsk_deqtimer endp
;
.tsk_ecode
end