; =============================================================================
;
; Litos - Task lock
;
; =============================================================================
CODE_SECTION 32
; ------------- Macro - initialized task lock
%macro TLOCK 0
LISTHEAD ; list of locked tasks
SPINLOCK ; lock of task list
%endmacro
; ------------- Macro - initialized task lock with lockable data
; %1 = pointer to lockable data
%macro TLOCKD 1
TLOCK ; initialized task lock
dd %1 ; pointer to lockable data
%endmacro
; ------------- Macro - initialized task lock with integer variable
; %1 = pointer to lockable data, %2 = reference value LOW,
; %3 = reference value HIGH, %4 = value to set LOW, %5 = value to set HIGH
%macro TLOCKV 5
TLOCKD %1 ; initialized task lock with data
dd %2, %3 ; reference value
dd %4, %5 ; value to set
%endmacro
; ------------- Macro - initialize task lock (%1 = pointer to TASKLOCK)
%macro TLOCK_Init 1
LISTINIT %1 ; initialize task list head
%ifdef SMP
LOCK2_Init (%1+TLOCK_Lock) ; initialize lock of task list
%endif
%endmacro
; ------------- Macro - initialize task lock
; %1 = pointer to TASKLOCK, EAX = 0, destroys EAX
%macro TLOCK0_Init 1
LISTINIT %1 ; initialize task list head
%ifdef SMP
LOCK0_Init (%1+TLOCK_Lock) ; initialize lock of task list
%endif
%endmacro
; ------------- Macro - initialize task lock
; %1 = pointer to TASKLOCK, EAX = 1
%macro TLOCK1_Init 1
LISTINIT %1 ; initialize task list head
%ifdef SMP
LOCK1_Init (%1+TLOCK_Lock) ; initialize lock of task list
%endif
%endmacro
; -----------------------------------------------------------------------------
; Macro - task lock callback function (integer variable)
; -----------------------------------------------------------------------------
; INPUT:
; EBX = pointer to TASKLOCK
; EDX = pointer to data
; %1 = operand size: 0=byte, 1=word, 2=double word, 3=quadruple word
; %2 = operand signification: 0=signed, 1=unsigned
; %3 = operation: 0=nothing, 1=set value, 2=increment, 3=decrement
; %4 = test: 0=false, 1=true, 2="=", 3="!=", 4="<", 5="<=", 6=">", 7=">="
; OUTPUT:
; AL = 0: false, 1: true (condition accomplished)
; DESTROYS: rest of EAX
; -----------------------------------------------------------------------------
; Currently not used.
%ifdef _UNUSED_
%macro TLV_FNC 4
CODE_SECTION 32
TLV %+ %1 %+ %2 %+ %3 %+ %4:
; ------------- Push registers
%if ((%3!=0)||(%4>1))&&(%1==3)
push ecx ; push ECX
%endif
; ------------- Load data (-> ECX:EAX)
%if (%3!=0)||(%4>1)
%if (%3!=1)
%if (%1==0)
mov al,[edx] ; AL <- data byte
%elif (%1==1)
mov ax,[edx] ; AX <- data word
%else
mov eax,[edx] ; EAX <- data double word
%if (%1==3)
mov ecx,[edx+4] ; ECX <- data quadruple word HIGH
%endif
%endif
%else
%if (%1==0)
mov al,[ebx+TLOCK_Set] ; AL <- data byte
%elif (%1==1)
mov ax,[ebx+TLOCK_Set] ; AX <- data word
%else
mov eax,[ebx+TLOCK_Set] ; EAX <- data double word
%if (%1==3)
mov ecx,[ebx+TLOCK_Set+4] ; ECX <- data qword HIGH
%endif
%endif
%endif
; ------------- Operation with data
%if (%3==2)
inc eax ; increment data
%if (%1==3)
jnz %%TLV1
inc ecx ; increment data HIGH
%%TLV1:
%endif
%elif (%3==3)
dec eax ; decrement data
%if (%1==3)
jnz %%TLV2
dec ecx ; decrement data HIGH
%%TLV2:
%endif
%endif
; ------------- Store new data
%if (%3!=0)
%if (%1==0)
mov [edx],al ; store data byte
%elif (%1==1)
mov [edx],ax ; store data word
%else
mov [edx],eax ; store data double word
%if (%1==3)
mov [edx+4],ecx ; store data quadruple word HIGH
%endif
%endif
%endif
; ------------- Compare data
%if (%4>1)
%if (%1==0)
cmp al,[ebx+TLOCK_Ref] ; compare data byte
%elif (%1==1)
cmp ax,[ebx+TLOCK_Ref] ; compare data word
%else
%if (%1==3)
cmp ecx,[ebx+TLOCK_Ref+4] ; compare data qword HIGH
jne %%TLV3
%endif
cmp eax,[ebx+TLOCK_Ref] ; compare data double word
%%TLV3:
%endif
%endif
%endif
; ------------- Condition
%if (%4==0)
mov al,0 ; false
%elif (%4==1)
mov al,1 ; true
%elif (%4==2)
sete al ; =
%elif (%4==3)
setne al ; !=
%else
%if (%2 == 0)
%if (%4==4)
setl al ; < signed
%elif (%4==5)
setle al ; <= signed
%elif (%4==6)
setg al ; > signed
%else
setge al ; >= signed
%endif
%else
%if (%4==4)
setb al ; < unsigned
%elif (%4==5)
setbe al ; <= unsigned
%elif (%4==6)
seta al ; > unsigned
%else
setae al ; >= unsigned
%endif
%endif
%endif
; ------------- Pop registers
%if ((%3!=0)||(%4>1))&&(%1==3)
pop ecx ; pop ECX
%endif
ret
CONST_SECTION
dd TLV %+ %1 %+ %2 %+ %3 %+ %4
%endmacro
; -----------------------------------------------------------------------------
; Macro - task lock callback function (bit variable)
; -----------------------------------------------------------------------------
; INPUT:
; EBX = popinter to TASKLOCK
; EDX = pointer to data byte
; %1 = bit number (0 to 7)
; %2 = operation: 0=nothing, 1=set bit, 2=reset bit, 3=complement bit
; %3 = test: 0=false, 1=true, 2=bit was set, 3=bit was reset
; OUTPUT:
; AL = 0: false, 1: true (condition accomplished)
; NOTES: Test is accomplished before bit operation.
; -----------------------------------------------------------------------------
%macro TLB_FNC 3
CODE_SECTION 32
TLB %+ %1 %+ %2 %+ %3:
; ------------- Test
%if (%3==0)
mov al,0 ; false
%elif (%3==1)
mov al,1 ; true
%else
test byte [edx],1<<%1 ; test bit
%if (%3==2)
setnz al ; bit is set
%else
setz al ; bit is reset
%endif
%endif
; ------------- Operation
%if (%2==1)
or byte [edx],1<<%1 ; set bit
%elif (%2==2)
and byte [edx],~(1<<%1) ; reset bit
%elif (%2==3)
xor byte [edx],1<<%1 ; complement bit
%endif
ret
CONST_SECTION
dd TLB %+ %1 %+ %2 %+ %3
%endmacro
; -----------------------------------------------------------------------------
; Standard task lock callback functions
; -----------------------------------------------------------------------------
CONST_SECTION
[list -]
; ------------- Integer variable
align 4, db 0
TLCallbackVar:
%assign TL_ARG4 0 ; argument 4 - condition
%rep 8
%assign TL_ARG3 0 ; argument 3 - operation
%rep 4
%assign TL_ARG2 0 ; argument 2 - signification
%rep 2
%assign TL_ARG1 0 ; argument 1 - operand size
%rep 4
TLV_FNC TL_ARG1, TL_ARG2, TL_ARG3, TL_ARG4
%assign TL_ARG1 TL_ARG1+1
%endrep
%assign TL_ARG2 TL_ARG2+1
%endrep
%assign TL_ARG3 TL_ARG3+1
%endrep
%assign TL_ARG4 TL_ARG4+1
%endrep
; ------------- Bit variable
align 4, db 0
TLCallbackBit:
%assign TL_ARG3 0 ; argument 3 - test
%rep 4
%assign TL_ARG2 0 ; argument 2 - operation
%rep 4
%assign TL_ARG1 0 ; argument 1 - bit number
%rep 8
TLB_FNC TL_ARG1, TL_ARG2, TL_ARG3
%assign TL_ARG1 TL_ARG1+1
%endrep
%assign TL_ARG2 TL_ARG2+1
%endrep
%assign TL_ARG3 TL_ARG3+1
%endrep
CODE_SECTION 32
[list +]
%endif ; _UNUSED_
; -----------------------------------------------------------------------------
; Initialize task lock
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock TASKLOCK
; -----------------------------------------------------------------------------
TaskLockInit: TLOCK_Init ebx ; initialize task lock
ret
; -----------------------------------------------------------------------------
; Initialize task lock with lockable data
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock TASKLOCKD
; EDX = pointer to lockable data
; -----------------------------------------------------------------------------
TaskLockDInit: call TaskLockInit ; initialize task lock
mov [ebx+TLOCK_Data],edx ; store pointer to data
ret
; -----------------------------------------------------------------------------
; Initialize task lock with integer variable (byte, word or double word)
; -----------------------------------------------------------------------------
; INPUT: EAX = reference value to compare
; EBX = task lock TASKLOCKV
; ECX = value to set
; EDX = pointer to lockable data
; -----------------------------------------------------------------------------
TaskLockIntInit:call TaskLockDInit ; initialize task lock with data
mov [ebx+TLOCK_Ref],eax ; store reference value
and dword [ebx+TLOCK_Ref+4],byte 0 ; ref. value HIGH
mov [ebx+TLOCK_Set],ecx ; store value to set
and dword [ebx+TLOCK_Set+4],byte 0 ; value to set HIGH
ret
; -----------------------------------------------------------------------------
; Initialize task lock with quadruple word integer variable
; -----------------------------------------------------------------------------
; INPUT: ESI:EAX = reference value to compare
; EBX = task lock TASKLOCKV
; EDI:ECX = value to set
; EDX = pointer to lockable data
; -----------------------------------------------------------------------------
TaskLockQWInit: call TaskLockDInit ; initialize task lock with data
mov [ebx+TLOCK_Ref],eax ; store reference value LOW
mov [ebx+TLOCK_Ref+4],esi ; clear ref. value HIGH
mov [ebx+TLOCK_Set],ecx ; store value to set
mov [ebx+TLOCK_Set+4],edi ; store value to set HIGH
ret
; -----------------------------------------------------------------------------
; Task lock sleep
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock TASKLOCK
; NOTES: It waits infinitely for an event. If event has not came after
; returning, TaskSleep can be called again.
; -----------------------------------------------------------------------------
; ------------- Push registers
TaskSleep: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
lea esi,[ebx+TLOCK_Lock] ; EDX <- lock of task list
call SpinLockESI ; lock task list
%endif
; ------------- Prepare task list entry (-> ECX)
CURRENT ecx ; ECX <- current task
add ecx,TASK_TaskList ; ECX <- task list entry
; ------------- Add this task to task list
mov eax,ecx ; EAX <- task list entry
mov [ecx-TASK_TaskList+TASK_TaskLock],ebx ; store task lock
call ListLast ; add task to end of list
; ------------- Prepare to fall asleep task
xor edx,edx ; EDX <- 0
dec edx ; EDX <- -1 (infinitely sleep time)
call PrepSleepTask ; prepare to fall asleep task
; ------------- Unlock task list
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Call scheduler (and switch to another task)
call Schedule ; call scheduler
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
call SpinLockESI ; lock task list
%endif
; ------------- Remove task from task list
xchg eax,ecx ; EAX <- task list entry
call ListDel ; remove task from task list
inc edx ; EDX <- 0
mov [eax-TASK_TaskList+TASK_TaskLock],edx ; clear task lock
; ------------- Unlock task list
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Task lock sleep with time-out
; -----------------------------------------------------------------------------
; INPUT: EAX = wait period (in [ms], negative=infinitely)
; EBX = task lock TASKLOCK
; OUTPUT: CY = time-out
; NOTES: It waits for a given time for an event. If event has not came
; after returning, TaskCont should be called.
; -----------------------------------------------------------------------------
; ------------- Push registers (it must be the same as in TaskContTime)
TaskSleepTime: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
lea esi,[ebx+TLOCK_Lock] ; EDX <- lock of task list
call SpinLockESI ; lock task list
%endif
; ------------- Prepare to fall asleep task
xchg eax,edx ; EDX <- wait time
or edx,edx ; negative time (infinitely)?
js TaskSleepTime2 ; negative time (infinitely)
mov eax,TIME_1MS ; EAX <- time 1 ms
mul edx ; recalc time to 100-ns
TaskSleepTime2: call PrepSleepTask ; prepare to fall asleep task
; ------------- Prepare task list entry (-> ECX) (TaskCont jumps here)
TaskSleepTime4: CURRENT ecx ; ECX <- current task
add ecx,TASK_TaskList ; ECX <- task list entry
; ------------- Add this task to task list
mov eax,ecx ; EAX <- task list entry
mov [ecx-TASK_TaskList+TASK_TaskLock],ebx ; store task lock
call ListLast ; add task to end of list
; ------------- Unlock task list
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Call scheduler (and switch to another task)
call Schedule ; call scheduler
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
call SpinLockESI ; lock task list
%endif
; ------------- Remove task from task list
xchg eax,ecx ; EAX <- task list entry
call ListDel ; remove task from task list
xor edx,edx ; EDX <- 0
mov [eax-TASK_TaskList+TASK_TaskLock],edx ; clear task lock
; ------------- Check if time expired
cmp edx,[eax-TASK_TaskList+TASK_Alarm+ALARM_Expire] ; LOW
jne TaskSleepTime8 ; time didn't expire
cmp edx,[eax-TASK_TaskList+TASK_Alarm+ALARM_Expire+4]; HIGH
je TaskSleepTime9 ; sleep time expired
; ------------- OK: Unlock task list
TaskSleepTime8:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
clc ; clear error flag
ret
; ------------- ERROR: Unlock task list
TaskSleepTime9:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop edx ; pop EDX
pop ecx ; pop ECX
pop eax ; pop EAX
stc ; set error flag
ret
; -----------------------------------------------------------------------------
; Continue task lock sleep with time-out
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock TASKLOCK
; OUTPUT: CY = time-out
; NOTES: It should be called after TaskSleepTime if event has not came.
; -----------------------------------------------------------------------------
; ------------- Push registers (it must be the same as in TaskSleepTime)
TaskCont: push eax ; push EAX
push ecx ; push ECX
push edx ; push EDX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
lea esi,[ebx+TLOCK_Lock] ; EDX <- lock of task list
call SpinLockESI ; lock task list
%endif
; ------------- Prepare to continue task sleep
call PrepSleepCont ; prepare to continue task sleep
jmp short TaskSleepTime4
; -----------------------------------------------------------------------------
; Task lock sleep with callback function
; -----------------------------------------------------------------------------
; INPUT: EAX = wait period (in [ms], 0=no wait, negative=infinitely)
; EBX = task lock TASKLOCK
; ECX = callback function
; INPUT: EBX = task lock TASKLOCK
; EDX = callback function data (pointer to data)
; OUTPUT: AL = 0: go sleep (and repeat test)
; AL <> 0: continue, returns NC
; EDX = callback function data (e.g. pointer to data)
; OUTPUT: CY = time-out, NC = condition OK
; -----------------------------------------------------------------------------
; ------------- Push registers
TaskSleepFnc: push eax ; push EAX
%ifdef SMP
push esi ; push ESI
%endif
push edi ; push EDI
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
lea esi,[ebx+TLOCK_Lock] ; EDX <- lock of task list
call SpinLockESI ; lock task list
%endif
; ------------- Test lock condition
push eax ; push EAX
call ecx ; callback function
or al,al ; continue?
pop eax ; pop EAX
jnz TaskSleepFnc8 ; continue with condition OK
; ------------- Check if wait for lock condition
or eax,eax ; wait for lock condition?
jz TaskSleepFnc9 ; don't wait for lock condition
; ------------- Prepare to fall asleep task
push edx ; push EDX
xchg eax,edx ; EDX <- wait time
or edx,edx ; negative time (infinitely)?
js TaskSleepFnc2 ; negative time (infinitely)
mov eax,TIME_1MS ; EAX <- time 1 ms
mul edx ; recalc time to 100-ns
TaskSleepFnc2: call PrepSleepTask ; prepare to fall asleep task
pop edx ; pop EDX
; ------------- Prepare task list entry (-> EDI)
TaskSleepFnc4: CURRENT edi ; EDI <- current task
add edi,TASK_TaskList ; EDI <- task list entry
; ------------- Add this task to task list
mov eax,edi ; EAX <- task list entry
mov [eax-TASK_TaskList+TASK_TaskLock],ebx ; store task lock
call ListLast ; add task to end of list
; ------------- Unlock task list
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Call scheduler (and switch to another task)
call Schedule ; call scheduler
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
call SpinLockESI ; lock task list
%endif
; ------------- Remove task from task list
xchg eax,edi ; EAX <- task list entry
call ListDel ; remove task from task list
xor edi,edi ; EDI <- 0
mov [eax-TASK_TaskList+TASK_TaskLock],edi ; clear task lock
; ------------- Test lock condition
push eax ; push EAX
call ecx ; callback function
or al,al ; continue with condition OK?
pop eax ; pop EAX
jnz TaskSleepFnc8 ; condition OK
; ------------- Check if time expired
cmp edi,[eax-TASK_TaskList+TASK_Alarm+ALARM_Expire] ; LOW
jne TaskSleepFnc6 ; time didn't expire
cmp edi,[eax-TASK_TaskList+TASK_Alarm+ALARM_Expire+4]; HIGH
je TaskSleepFnc9 ; sleep time expired
; ------------- Prepare to continue task sleep
TaskSleepFnc6: call PrepSleepCont ; prepare to continue task sleep
jmp short TaskSleepFnc4 ; continue sleep
; ------------- OK: Unlock task list
TaskSleepFnc8:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
pop edi ; pop EDI
%ifdef SMP
pop esi ; pop ESI
%endif
pop eax ; pop EAX
clc ; clear error flag
ret
; ------------- ERROR: Unlock task list
TaskSleepFnc9:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
pop edi ; pop EDI
%ifdef SMP
pop esi ; pop ESI
%endif
pop eax ; pop EAX
stc ; set error flag
ret
; -----------------------------------------------------------------------------
; Task lock sleep with integer variable
; -----------------------------------------------------------------------------
; INPUT: EAX = wait period (in [ms], 0=no wait, negative=infinitely)
; EBX = task lock with integer variable TASKLOCKV
; CL = callback function flags for integer variable
; (TLOCK_BYTE,... TLOCK_GE)
; OUTPUT: CY = time-out, NC = condition OK
; -----------------------------------------------------------------------------
; Currently not used.
%ifdef _UNUSED_
; ------------- Push registers
TaskLockInt: push ecx ; push ECX
push edx ; push EDX
; ------------- Call task lock sleep
movzx ecx,cl ; ECX <- flags
mov ecx,[TLCallbackVar+ecx*4] ; ECX <- callback function
mov edx,[ebx+TLOCK_Data] ; EDX <- pointer to data
call TaskSleepFnc ; call task lock sleep
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Task lock sleep with bit variable
; -----------------------------------------------------------------------------
; INPUT: EAX = wait period (in [ms], 0=no wait, negative=infinitely)
; EBX = task lock with lockable data TASKLOCKD
; CL = callback function flags for bit variable
; (TLOCK_BIT0,... TLOCK_BITWASRES)
; OUTPUT: CY = time-out, NC = condition OK
; -----------------------------------------------------------------------------
; ------------- Push registers
TaskLockBit: push ecx ; push ECX
push edx ; push EDX
; ------------- Call task lock sleep
and ecx,7fh ; ECX <- flags
mov ecx,[TLCallbackBit+ecx*4] ; ECX <- callback function
mov edx,[ebx+TLOCK_Data] ; EDX <- pointer to data
call TaskSleepFnc ; call task lock sleep
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
ret
%endif ; _UNUSED_
; -----------------------------------------------------------------------------
; Task lock wake-up
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock TASKLOCK
; -----------------------------------------------------------------------------
; ------------- Push registers
TaskWakeUp: push eax ; push EAX
push ebx ; push EBX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
lea esi,[ebx+TLOCK_Lock] ; EDX <- lock of task list
call SpinLockESI ; lock task list
%endif
; ------------- Get next task (-> EBX)
mov eax,[ebx+LIST_Next] ; EAX <- next task
cmp eax,ebx ; is task list empty?
je TaskWakeUp8 ; no other task in the list
sub eax,TASK_TaskList ; EAX <- task
xchg eax,ebx ; EBX <- task
; ------------- Clear fall asleep state
cmp byte [ebx+TASK_State],TASK_FALLASLEEP ; fall asleep?
jne TaskWakeUp4 ; task is not going to fall asleep
mov byte [ebx+TASK_State],TASK_RUNNING ; mark as running
jmp short TaskWakeUp8
; ------------- Wake-up next task
TaskWakeUp4: call WakeUpTask ; wake-up task
; ------------- Unlock task list
TaskWakeUp8:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop ebx ; pop EBX
pop eax ; pop EAX
ret
; -----------------------------------------------------------------------------
; Task lock wake-up with callback function
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock TASKLOCK
; ECX = callback function
; INPUT: EBX = task lock TASKLOCK
; EDX = callback function data (pointer to data)
; OUTPUT: AL = 0: returns CY
; AL <> 0: wake-up next task, returns NC
; EDX = callback function data (e.g. pointer to data)
; OUTPUT: CY = condition not accomplished, NC = condition OK
; NOTES: Next task waked-up if condition accomplished.
; -----------------------------------------------------------------------------
; ------------- Push registers
TaskWakeUpFnc: push eax ; push EAX
push ebx ; push EBX
%ifdef SMP
push esi ; push ESI
%endif
; ------------- Disable interrupts
pushf ; push flags
cli ; disable interrupts
; ------------- Lock task list
%ifdef SMP
lea esi,[ebx+TLOCK_Lock] ; EDX <- lock of task list
call SpinLockESI ; lock task list
%endif
; ------------- Call callback function
call ecx ; callback function
or al,al ; continue?
jz TaskWakeUpFnc9 ; condition not accomplished
; ------------- Get next task (-> EBX)
mov eax,[ebx+LIST_Next] ; EAX <- first task
cmp eax,ebx ; is task list empty?
je TaskWakeUpFnc8 ; no task in the list
sub eax,TASK_TaskList ; EAX <- task
xchg eax,ebx ; EBX <- task
; ------------- Clear fall asleep state
cmp byte [ebx+TASK_State],TASK_FALLASLEEP ; fall asleep?
jne TaskWakeUpFnc6 ; task is not going to fall asleep
mov byte [ebx+TASK_State],TASK_RUNNING ; mark as running
jmp short TaskWakeUpFnc8
; ------------- Wake-up next task
TaskWakeUpFnc6: call WakeUpTask ; wake-up task
; ------------- OK: Unlock task list
TaskWakeUpFnc8:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop ebx ; pop EBX
pop eax ; pop EAX
clc ; clear error flag
ret
; ------------- ERROR: Unlock task list
TaskWakeUpFnc9:
%ifdef SMP
LOCK_Unlock esi ; unlock task list
%endif
; ------------- Enable interrupts
popf ; pop flags
; ------------- Pop registers
%ifdef SMP
pop esi ; pop ESI
%endif
pop ebx ; pop EBX
pop eax ; pop EAX
stc ; set error flag
ret
; -----------------------------------------------------------------------------
; Task lock wake-up with integer variable
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock with integer variable TASKLOCKV
; CL = callback function flags for integer variable
; (TLOCK_BYTE,... TLOCK_GE)
; OUTPUT: CY = condition not accomplished, NC = condition OK
; NOTES: Next task waked-up if condition accomplished.
; -----------------------------------------------------------------------------
; Currently not used.
%ifdef _UNUSED_
; ------------- Push registers
TaskUnlockInt: push ecx ; push ECX
push edx ; push EDX
; ------------- Call task lock sleep
movzx ecx,cl ; ECX <- flags
mov ecx,[TLCallbackVar+ecx*4] ; ECX <- callback function
mov edx,[ebx+TLOCK_Data] ; EDX <- pointer to data
call TaskWakeUpFnc ; call task lock wake-up
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
ret
; -----------------------------------------------------------------------------
; Task lock wake-up with bit variable
; -----------------------------------------------------------------------------
; INPUT: EBX = task lock with lockable data TASKLOCKD
; CL = callback function flags for bit variable
; (TLOCK_BIT0,... TLOCK_BITWASRES)
; OUTPUT: CY = condition not accomplished, NC = condition OK
; NOTES: Next task waked-up if condition accomplished.
; -----------------------------------------------------------------------------
; ------------- Push registers
TaskUnlockBit: push ecx ; push ECX
push edx ; push EDX
; ------------- Call task lock sleep
and ecx,7fh ; ECX <- flags
mov ecx,[TLCallbackBit+ecx*4] ; ECX <- callback function
mov edx,[ebx+TLOCK_Data] ; EDX <- pointer to data
call TaskWakeUpFnc ; call task lock wake-up
; ------------- Pop registers
pop edx ; pop EDX
pop ecx ; pop ECX
ret
%endif ; _UNUSED_
|