1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
| __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
|