Subversion Repositories Kolibri OS

Rev

Rev 3617 | Rev 5130 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2288 clevermous 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2455 mario79 3
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
2288 clevermous 4
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
5
;; Distributed under terms of the GNU General Public License    ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
8
$Revision: 4700 $
9
 
10
 
11
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12
;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
13
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
 
15
 
16
align 32
17
irq0:
18
        pushad
19
        Mov     ds, ax, app_data
20
        mov     es, ax
21
        inc     [timer_ticks]
22
        mov     eax, [timer_ticks]
23
        call    playNote       ; <<<--- Speaker driver
24
        sub     eax, [next_usage_update]
25
        cmp     eax, 100
26
        jb      .nocounter
27
        add     [next_usage_update], 100
28
        call    updatecputimes
29
  .nocounter:
30
        xor     ecx, ecx        ; send End Of Interrupt signal
31
        call    irq_eoi
4700 mario79 32
 
3615 clevermous 33
        mov     bl, SCHEDULE_ANY_PRIORITY
2288 clevermous 34
        call    find_next_task
35
        jz      .return  ; if there is only one running process
36
        call    do_change_task
37
  .return:
38
        popad
39
        iretd
40
 
41
align 4
42
change_task:
43
        pushfd
44
        cli
45
        pushad
3615 clevermous 46
        mov     bl, SCHEDULE_ANY_PRIORITY
2288 clevermous 47
        call    find_next_task
48
        jz      .return  ; the same task -> skip switch
4700 mario79 49
 
2288 clevermous 50
        call    do_change_task
51
  .return:
52
        popad
53
        popfd
54
        ret
55
 
56
uglobal
57
align 4
58
;  far_jump:
59
;   .offs dd ?
60
;   .sel  dw ?
61
   context_counter     dd 0 ;noname & halyavin
62
   next_usage_update   dd 0
63
   timer_ticks         dd 0
64
;  prev_slot           dd ?
65
;  event_sched         dd ?
66
endg
67
 
68
align 4
69
update_counters:
70
        mov     edi, [TASK_BASE]
71
        rdtsc
72
        sub     eax, [edi+TASKDATA.counter_add] ; time stamp counter add
73
        add     [edi+TASKDATA.counter_sum], eax ; counter sum
74
        ret
75
align 4
76
updatecputimes:
77
        mov     ecx, [TASK_COUNT]
78
        mov     edi, TASK_DATA
79
  .newupdate:
80
        xor     eax, eax
81
        xchg    eax, [edi+TASKDATA.counter_sum]
82
        mov     [edi+TASKDATA.cpu_usage], eax
83
        add     edi, 0x20
84
        loop    .newupdate
85
        ret
86
 
3539 clevermous 87
;TODO: Надо бы убрать использование do_change_task из V86...
88
; и после этого перенести обработку TASKDATA.counter_add/sum в do_change_task
2288 clevermous 89
 
90
align 4
91
do_change_task:
92
;param:
93
;   ebx = address of the APPDATA for incoming task (new)
94
;warning:
95
;   [CURRENT_TASK] and [TASK_BASE] must be changed before (e.g. in find_next_task)
96
;   [current_slot] is the outcoming (old), and set here to a new value (ebx)
97
;scratched: eax,ecx,esi
98
        mov     esi, ebx
99
        xchg    esi, [current_slot]
100
; set new stack after saving old
101
        mov     [esi+APPDATA.saved_esp], esp
102
        mov     esp, [ebx+APPDATA.saved_esp]
103
; set new thread io-map
104
        Mov     dword [page_tabs+((tss._io_map_0 and -4096) shr 10)],eax,[ebx+APPDATA.io_map]
105
        Mov     dword [page_tabs+((tss._io_map_1 and -4096) shr 10)],eax,[ebx+APPDATA.io_map+4]
106
; set new thread memory-map
107
        mov     ecx, APPDATA.dir_table
108
        mov     eax, [ebx+ecx]      ;offset>0x7F
109
        cmp     eax, [esi+ecx]      ;offset>0x7F
110
        je      @f
111
        mov     cr3, eax
112
@@:
113
; set tss.esp0
114
 
115
        Mov     [tss._esp0],eax,[ebx+APPDATA.saved_esp0]
116
 
117
        mov     edx, [ebx+APPDATA.tls_base]
118
        cmp     edx, [esi+APPDATA.tls_base]
119
        je      @f
120
 
121
        mov     [tls_data_l+2], dx
122
        shr     edx, 16
123
        mov     [tls_data_l+4], dl
124
        mov     [tls_data_l+7], dh
125
 
126
        mov     dx, app_tls
127
        mov     fs, dx
128
@@:
129
; set gs selector unconditionally
130
        Mov     gs,ax,graph_data
131
      ; set CR0.TS
132
        cmp     bh, byte[fpu_owner] ;bh == incoming task (new)
133
        clts                        ;clear a task switch flag
134
        je      @f
135
        mov     eax, cr0            ;and set it again if the owner
136
        or      eax, CR0_TS         ;of a fpu has changed
137
        mov     cr0, eax
138
  @@: ; set context_counter (only for user pleasure ???)
139
        inc     [context_counter]   ;noname & halyavin
140
      ; set debug-registers, if it's necessary
141
        test    byte[ebx+APPDATA.dbg_state], 1
142
        jz      @f
143
        xor     eax, eax
144
        mov     dr6, eax
145
        lea     esi, [ebx+ecx+APPDATA.dbg_regs-APPDATA.dir_table];offset>0x7F
146
        cld
147
  macro lodsReg [reg] {
148
        lodsd
149
        mov     reg, eax
150
  }     lodsReg dr0, dr1, dr2, dr3, dr7
151
  purge lodsReg
152
  @@:
153
        ret
154
;end.
155
 
156
 
157
 
2381 hidnplayr 158
struct  MUTEX_WAITER
159
        list    LHEAD
160
        task    dd ?
161
ends
2288 clevermous 162
 
163
;void  __fastcall mutex_init(struct mutex *lock)
164
 
165
align 4
166
mutex_init:
2381 hidnplayr 167
        mov     [ecx+MUTEX.lhead.next], ecx
168
        mov     [ecx+MUTEX.lhead.prev], ecx
2288 clevermous 169
        mov     [ecx+MUTEX.count], 1
170
        ret
171
 
172
 
173
;void  __fastcall mutex_lock(struct mutex *lock)
174
 
175
align 4
176
mutex_lock:
177
 
178
        dec     [ecx+MUTEX.count]
179
        jns     .done
180
 
181
        pushfd
182
        cli
183
 
2381 hidnplayr 184
        sub     esp, sizeof.MUTEX_WAITER
2288 clevermous 185
 
186
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
187
 
188
        mov     edx, [TASK_BASE]
189
        mov     [esp+MUTEX_WAITER.task], edx
190
 
191
.forever:
192
 
193
        mov     eax, -1
194
        xchg    eax, [ecx+MUTEX.count]
195
        dec     eax
196
        jz      @F
197
 
198
        mov     [edx+TASKDATA.state], 1
199
        call    change_task
200
        jmp     .forever
201
@@:
202
        mov     edx, [esp+MUTEX_WAITER.list.next]
203
        mov     eax, [esp+MUTEX_WAITER.list.prev]
204
 
205
        mov     [eax+MUTEX_WAITER.list.next], edx
206
        mov     [edx+MUTEX_WAITER.list.prev], eax
2381 hidnplayr 207
        cmp     [ecx+MUTEX.lhead.next], ecx
2288 clevermous 208
        jne     @F
209
 
210
        mov     [ecx+MUTEX.count], 0
211
@@:
2381 hidnplayr 212
        add     esp, sizeof.MUTEX_WAITER
2288 clevermous 213
 
214
        popfd
215
.done:
216
        ret
217
 
218
;void  __fastcall mutex_unlock(struct mutex *lock)
219
 
220
align 4
221
mutex_unlock:
222
 
223
        pushfd
224
        cli
225
 
2381 hidnplayr 226
        mov     eax, [ecx+MUTEX.lhead.next]
2288 clevermous 227
        cmp     eax, ecx
228
        mov     [ecx+MUTEX.count], 1
229
        je      @F
230
 
231
        mov     eax, [eax+MUTEX_WAITER.task]
232
        mov     [eax+TASKDATA.state], 0
233
@@:
234
        popfd
235
        ret
236
 
237
 
238
purge MUTEX_WAITER
239
 
3534 clevermous 240
MAX_PRIORITY      = 0   ; highest, used for kernel tasks
241
USER_PRIORITY     = 1   ; default
242
IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
243
NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
244
 
245
uglobal
246
; [scheduler_current + i*4] = zero if there are no threads with priority i,
247
;  pointer to APPDATA of the current thread with priority i otherwise.
248
align 4
249
scheduler_current       rd      NR_SCHED_QUEUES
250
endg
251
 
252
; Add the given thread to the given priority list for the scheduler.
253
; in: edx -> APPDATA, ecx = priority
254
proc scheduler_add_thread
255
; 1. Acquire the lock.
256
        spin_lock_irqsave SchedulerLock
257
; 2. Store the priority in APPDATA structure.
258
        mov     [edx+APPDATA.priority], ecx
259
; 3. There are two different cases: the given list is empty or not empty.
260
; In first case, go to 6. Otherwise, advance to 4.
261
        mov     eax, [scheduler_current+ecx*4]
262
        test    eax, eax
263
        jz      .new_list
264
; 4. Insert the new item immediately before the current item.
265
        mov     ecx, [eax+APPDATA.in_schedule.prev]
266
        mov     [edx+APPDATA.in_schedule.next], eax
267
        mov     [edx+APPDATA.in_schedule.prev], ecx
268
        mov     [eax+APPDATA.in_schedule.prev], edx
269
        mov     [ecx+APPDATA.in_schedule.next], edx
270
; 5. Release the lock and return.
271
        spin_unlock_irqrestore SchedulerLock
272
        ret
273
.new_list:
274
; 6. Initialize the list with one item and make it the current item.
275
        mov     [edx+APPDATA.in_schedule.next], edx
276
        mov     [edx+APPDATA.in_schedule.prev], edx
277
        mov     [scheduler_current+ecx*4], edx
278
; 7. Release the lock and return.
279
        spin_unlock_irqrestore SchedulerLock
280
        ret
281
endp
282
 
283
; Remove the given thread from the corresponding priority list for the scheduler.
284
; in: edx -> APPDATA
285
proc scheduler_remove_thread
286
; 1. Acquire the lock.
287
        spin_lock_irqsave SchedulerLock
288
; 2. Remove the item from the corresponding list.
289
        mov     eax, [edx+APPDATA.in_schedule.next]
290
        mov     ecx, [edx+APPDATA.in_schedule.prev]
291
        mov     [eax+APPDATA.in_schedule.prev], ecx
292
        mov     [ecx+APPDATA.in_schedule.next], eax
293
; 3. If the given thread is the current item in the list,
294
; advance the current item.
295
; 3a. Check whether the given thread is the current item;
296
; if no, skip the rest of this step.
297
        mov     ecx, [edx+APPDATA.priority]
298
        cmp     [scheduler_current+ecx*4], edx
299
        jnz     .return
300
; 3b. Set the current item to eax; step 2 has set eax = next item.
301
        mov     [scheduler_current+ecx*4], eax
302
; 3c. If there were only one item in the list, zero the current item.
303
        cmp     eax, edx
304
        jnz     .return
305
        mov     [scheduler_current+ecx*4], 0
306
.return:
307
; 4. Release the lock and return.
308
        spin_unlock_irqrestore SchedulerLock
309
        ret
310
endp
311
 
3615 clevermous 312
SCHEDULE_ANY_PRIORITY = 0
313
SCHEDULE_HIGHER_PRIORITY = 1
3534 clevermous 314
;info:
315
;   Find next task to execute
3615 clevermous 316
;in:
317
;   bl = SCHEDULE_ANY_PRIORITY:
318
;        consider threads with any priority
319
;   bl = SCHEDULE_HIGHER_PRIORITY:
320
;        consider only threads with strictly higher priority than the current one,
321
;        keep running the current thread if other ready threads have the same or lower priority
3534 clevermous 322
;retval:
323
;   ebx = address of the APPDATA for the selected task (slot-base)
324
;   edi = address of the TASKDATA for the selected task
325
;   ZF  = 1  if the task is the same
326
;warning:
327
;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
328
;   [current_slot] is not set to new value (ebx)!!!
329
;scratched: eax,ecx
330
proc find_next_task
331
        call    update_counters
332
        spin_lock_irqsave SchedulerLock
3615 clevermous 333
        push    NR_SCHED_QUEUES
334
; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
335
; Otherwise, loop over first [APPDATA.priority] lists.
336
        test    bl, bl
337
        jz      .start
338
        mov     ebx, [current_slot]
339
        mov     edi, [TASK_BASE]
340
        mov     eax, [ebx+APPDATA.priority]
341
        test    eax, eax
342
        jz      .unlock_found
343
        mov     [esp], eax
344
.start:
3534 clevermous 345
        xor     ecx, ecx
346
.priority_loop:
347
        mov     ebx, [scheduler_current+ecx*4]
348
        test    ebx, ebx
349
        jz      .priority_next
350
.task_loop:
351
        mov     ebx, [ebx+APPDATA.in_schedule.next]
352
        mov     edi, ebx
353
        shr     edi, 3
354
        add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
355
        mov     al, [edi+TASKDATA.state]
356
        test    al, al
357
        jz      .task_found     ; state == 0
358
        cmp     al, 5
359
        jne     .task_next      ; state == 1,2,3,4,9
360
      ; state == 5
361
        pushad  ; more freedom for [APPDATA.wait_test]
362
        call    [ebx+APPDATA.wait_test]
363
        mov     [esp+28], eax
364
        popad
365
        or      eax, eax
366
        jnz     @f
367
      ; testing for timeout
368
        mov     eax, [timer_ticks]
369
        sub     eax, [ebx+APPDATA.wait_begin]
370
        cmp     eax, [ebx+APPDATA.wait_timeout]
371
        jb      .task_next
372
        xor     eax, eax
373
@@:
374
        mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
375
        mov     [edi+TASKDATA.state], 0
376
.task_found:
377
        mov     [scheduler_current+ecx*4], ebx
3617 clevermous 378
; If we have selected a thread with higher priority
379
; AND rescheduling is due to IRQ,
380
; turn the current scheduler list one entry back,
381
; so the current thread will be next after high-priority thread is done.
382
        mov     ecx, [esp]
383
        cmp     ecx, NR_SCHED_QUEUES
384
        jz      .unlock_found
385
        mov     eax, [current_slot]
386
        mov     eax, [eax+APPDATA.in_schedule.prev]
387
        mov     [scheduler_current+ecx*4], eax
3615 clevermous 388
.unlock_found:
389
        pop     ecx
3534 clevermous 390
        spin_unlock_irqrestore SchedulerLock
391
.found:
392
        mov     [CURRENT_TASK], bh
393
        mov     [TASK_BASE], edi
394
        rdtsc   ;call  _rdtsc
395
        mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
396
        cmp     ebx, [current_slot]
397
        ret
398
.task_next:
399
        cmp     ebx, [scheduler_current+ecx*4]
400
        jnz     .task_loop
401
.priority_next:
402
        inc     ecx
3615 clevermous 403
        cmp     ecx, [esp]
3534 clevermous 404
        jb      .priority_loop
3615 clevermous 405
        mov     ebx, [current_slot]
406
        mov     edi, [TASK_BASE]
407
        jmp     .unlock_found
3534 clevermous 408
endp
409
 
2288 clevermous 410
if 0
411
 
412
struc TIMER
413
{
414
  .next      dd ?
415
  .exp_time  dd ?
416
  .func      dd ?
417
  .arg       dd ?
418
}
419
 
420
 
421
uglobal
422
rdy_head   rd 16
423
endg
424
 
425
align 4
426
pick_task:
427
 
428
        xor     eax, eax
429
  .pick:
430
        mov     ebx, [rdy_head+eax*4]
431
        test    ebx, ebx
432
        jz      .next
433
 
434
        mov     [next_task], ebx
435
        test    [ebx+flags.billable]
436
        jz      @F
437
        mov     [bill_task], ebx
438
  @@:
439
        ret
440
  .next:
441
        inc     eax
442
        jmp     .pick
443
 
444
; param
445
;  eax= task
446
;
447
; retval
448
;  eax= task
449
;  ebx= queue
450
;  ecx= front if 1 or back if 0
451
align 4
452
shed:
453
        cmp     [eax+.tics_left], 0;signed compare
454
        mov     ebx, [eax+.priority]
455
        setg    ecx
456
        jg      @F
457
 
458
        mov     edx, [eax+.tics_quantum]
459
        mov     [eax+.ticks_left], edx
460
        cmp     ebx, (IDLE_PRIORITY-1)
461
        je      @F
462
        inc     ebx
463
  @@:
464
        ret
465
 
466
; param
467
;  eax= task
468
align 4
469
enqueue:
470
        call    shed;eax
471
        cmp     [rdy_head+ebx*4], 0
472
        jnz     @F
473
 
474
        mov     [rdy_head+ebx*4], eax
475
        mov     [rdy_tail+ebx*4], eax
476
        mov     [eax+.next_ready], 0
477
        jmp     .pick
478
  @@:
479
        test    ecx, ecx
480
        jz      .back
481
 
482
        mov     ecx, [rdy_head+ebx*4]
483
        mov     [eax+.next_ready], ecx
484
        mov     [rdy_head+ebx*4], eax
485
        jmp     .pick
486
  .back:
487
        mov     ecx, [rdy_tail+ebx*4]
488
        mov     [ecx+.next_ready], eax
489
        mov     [rdy_tail+ebx*4], eax
490
        mov     [eax+.next_ready], 0
491
  .pick:
492
        call    pick_proc;select next task
493
        ret
494
 
495
end if