__sys_time_slice = 10 ;[ms]
uglobal
if used TimerCreate
__InternalTimerID dd ?
__InternalTimerThread dd ?
end if
endg
if used TimerCreate
initialize InitLinuxTimers
.action lnx_sigaction
.timer lnx_sigevent
.time lnx_itimerspec
begin
; set the signal handler.
mov eax, sys_sigaction
mov ebx, SIGALRM
lea ecx, [.action]
mov [ecx+lnx_sigaction.sa_handler], __TimerProc
mov [ecx+lnx_sigaction.sa_mask], 0
mov [ecx+lnx_sigaction.sa_flags], 0
xor edx, edx
int $80
; create the interval timer
mov eax, sys_timer_create
mov ebx, CLOCK_REALTIME
lea ecx, [.timer]
mov [ecx+lnx_sigevent.notify], SIGEV_SIGNAL
mov [ecx+lnx_sigevent.signo], SIGALRM
mov [ecx+lnx_sigevent.value], 0 ; not used but must be set - the function fails without it...
mov edx, __InternalTimerID
int $80
; stdcall OutputRegister, regEAX, 16
; then start a thread that will process timer expiration events.
stdcall ThreadCreate, __TimerHandler, 0
mov [__InternalTimerThread], eax
; start the timer
mov ebx, [__InternalTimerID]
mov eax, sys_timer_settime
lea edx, [.time]
mov [edx+lnx_itimerspec.it_interval.tv_sec], 0
mov [edx+lnx_itimerspec.it_interval.tv_nsec], __sys_time_slice*1000000
mov [edx+lnx_itimerspec.it_value.tv_sec], 0
mov [edx+lnx_itimerspec.it_value.tv_nsec], __sys_time_slice*1000000
xor esi, esi
int $80
; stdcall OutputRegister, regEAX, 16
return
endp
finalize FreeLinuxTimers
begin
; stop the timer
mov eax, sys_timer_delete
mov ebx, [__InternalTimerID]
int $80
; then stop the handling thread
mov eax, sys_kill
mov ebx, [__InternalTimerThread]
mov ecx, SIGTERM
int $80
return
endp
end if
; This procedure is called by the system on every time quantum.
;
proc __TimerProc, .signal
begin
push ebx esi edi
mov eax, sys_signal
lea eax, [__ptrFirstTimer]
xor edi, edi
.loop:
mov eax, [eax+TTimer.next]
test eax, eax
jz .end_timers
test [eax+TTimer.flags], tmfRunning
jz .loop
mov ecx, [eax+TTimer.value]
add ecx, __sys_time_slice
mov [eax+TTimer.value], ecx
cmp ecx, [eax+TTimer.interval]
jl .loop
; call event handler
cmp [eax+TTimer.Callback], 0
je .handlerok
push eax
mov ecx, [eax+TTimer.flags]
and ecx, $0f
cmp eax, tmfDoNothing
je .end_event
; run the timer event in separate thread:
inc [eax+TTimer.Expired]
inc edi
.end_event:
pop eax
test [eax+TTimer.flags], tmfSyncDestroy
jz .handlerok
stdcall TimerDestroy, eax
.handlerok:
; jump to loop
mov ecx, [eax+TTimer.interval]
sub [eax+TTimer.value], ecx
jmp .loop
.end_timers:
test edi, edi
jz @f
mov eax, sys_kill
mov ebx, [__InternalTimerThread]
mov ecx, SIGCONT
int $80
@@:
pop edi esi ebx
xor eax, eax
cret
endp
proc __TimerHandler, .dummy
.remain dd ?
.action lnx_sigaction
begin
mov eax, sys_sigaction
mov ebx, SIGCONT
lea ecx, [.action]
mov [ecx+lnx_sigaction.sa_handler], __dummy_proc
mov [ecx+lnx_sigaction.sa_mask], 0
mov [ecx+lnx_sigaction.sa_flags], SA_NODEFER
xor edx, edx
int $80
.from_begin:
mov [.remain], 0
lea eax, [__ptrFirstTimer]
.listloop:
mov eax, [eax+TTimer.next]
.listloop2:
test eax, eax
jz .end_list
mov ecx, [eax+TTimer.Expired]
jecxz .listloop
dec ecx
mov [eax+TTimer.Expired], ecx
add [.remain], ecx
cmp [eax+TTimer.Callback], 0
je .listloop
mov ecx, [eax+TTimer.flags]
and ecx, $0f
cmp ecx, tmfDoNothing
je .end_event
cmp ecx, tmfFireEvent
je .end_event ;.fire_event ; still not supported
; call the callback procedure.
pushad
stdcall [eax+TTimer.Callback], eax
popad
.end_event:
test [eax+TTimer.flags], tmfSyncDestroy
jz .listloop
push eax
mov eax, [eax+TTimer.next] ; after the destruction, this pointer will be lost.
stdcall TimerDestroy ; pointer from the stack.
jmp .listloop2
.end_list:
cmp [.remain], 0
jne .from_begin
mov eax, sys_pause
int $80
jmp .from_begin
endp
proc __dummy_proc, .dummy
begin
cret
endp