Subversion Repositories Kolibri OS

Rev

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

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