Subversion Repositories Kolibri OS

Rev

Rev 5130 | Rev 5344 | 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: 5343 $
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
5130 serge 107
        mov     eax, [ebx+APPDATA.process]
108
        cmp     eax, [current_process]
2288 clevermous 109
        je      @f
5130 serge 110
        mov     [current_process], eax
111
        mov     eax, [eax+PROC.pdt_0_phys]
2288 clevermous 112
        mov     cr3, eax
113
@@:
114
; set tss.esp0
115
 
116
        Mov     [tss._esp0],eax,[ebx+APPDATA.saved_esp0]
117
 
118
        mov     edx, [ebx+APPDATA.tls_base]
119
        cmp     edx, [esi+APPDATA.tls_base]
120
        je      @f
121
 
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
126
 
127
        mov     dx, app_tls
128
        mov     fs, dx
129
@@:
130
; set gs selector unconditionally
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
5130 serge 146
        lea     esi, [ebx+APPDATA.dbg_regs]
2288 clevermous 147
        cld
148
  macro lodsReg [reg] {
149
        lodsd
150
        mov     reg, eax
151
  }     lodsReg dr0, dr1, dr2, dr3, dr7
152
  purge lodsReg
153
  @@:
154
        ret
155
;end.
156
 
157
 
158
 
2381 hidnplayr 159
struct  MUTEX_WAITER
160
        list    LHEAD
161
        task    dd ?
5343 serge 162
        type    dd ?
2381 hidnplayr 163
ends
2288 clevermous 164
 
165
;void  __fastcall mutex_init(struct mutex *lock)
166
 
167
align 4
168
mutex_init:
5343 serge 169
        mov     [ecx+MUTEX.wait_list.next], ecx
170
        mov     [ecx+MUTEX.wait_list.prev], ecx
2288 clevermous 171
        mov     [ecx+MUTEX.count], 1
172
        ret
173
 
174
;void  __fastcall mutex_lock(struct mutex *lock)
175
 
176
align 4
177
mutex_lock:
178
 
179
        dec     [ecx+MUTEX.count]
180
        jns     .done
181
 
182
        pushfd
183
        cli
184
 
2381 hidnplayr 185
        sub     esp, sizeof.MUTEX_WAITER
2288 clevermous 186
 
187
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
188
 
189
        mov     edx, [TASK_BASE]
190
        mov     [esp+MUTEX_WAITER.task], edx
191
 
192
.forever:
193
 
194
        mov     eax, -1
195
        xchg    eax, [ecx+MUTEX.count]
196
        dec     eax
197
        jz      @F
198
 
199
        mov     [edx+TASKDATA.state], 1
200
        call    change_task
201
        jmp     .forever
202
@@:
5343 serge 203
        mov     eax, ecx
204
        list_del esp
2288 clevermous 205
 
5343 serge 206
        cmp     [eax+MUTEX.wait_list.next], eax
2288 clevermous 207
        jne     @F
208
 
5343 serge 209
        mov     [eax+MUTEX.count], 0
2288 clevermous 210
@@:
2381 hidnplayr 211
        add     esp, sizeof.MUTEX_WAITER
2288 clevermous 212
 
213
        popfd
214
.done:
215
        ret
216
 
217
;void  __fastcall mutex_unlock(struct mutex *lock)
218
 
219
align 4
220
mutex_unlock:
221
 
222
        pushfd
223
        cli
224
 
5343 serge 225
        mov     eax, [ecx+MUTEX.wait_list.next]
2288 clevermous 226
        cmp     eax, ecx
227
        mov     [ecx+MUTEX.count], 1
228
        je      @F
229
 
230
        mov     eax, [eax+MUTEX_WAITER.task]
231
        mov     [eax+TASKDATA.state], 0
232
@@:
233
        popfd
234
        ret
235
 
236
 
5343 serge 237
;void __fastcall down_read(struct rw_semaphore *sem)
238
 
239
align 4
240
down_read:
241
        pushfd
242
        cli
243
 
244
        mov     eax, [ecx+RWSEM.count]
245
        test    eax, eax
246
        js      @F
247
 
248
        cmp     ecx, [ecx+RWSEM.wait_list.next]
249
        je      .ok
250
@@:
251
        sub     esp, sizeof.MUTEX_WAITER
252
 
253
        mov     eax, [TASK_BASE]
254
        mov     [esp+MUTEX_WAITER.task], eax
255
        mov     [esp+MUTEX_WAITER.type], 1; RWSEM_WAITING_FOR_READ
256
        mov     [eax+TASKDATA.state], 1
257
 
258
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
259
 
260
        call    change_task
261
 
262
        add     esp, sizeof.MUTEX_WAITER
263
        popfd
264
        ret
265
.ok:
266
        inc     eax
267
        mov     [ecx+RWSEM.count], eax
268
 
269
        popfd
270
        ret
271
 
272
;void __fastcall down_write(struct rw_semaphore *sem)
273
 
274
align 4
275
down_write:
276
        pushfd
277
        cli
278
        sub     esp, sizeof.MUTEX_WAITER
279
 
280
        mov     edx, [TASK_BASE]
281
        mov     [esp+MUTEX_WAITER.task], edx
282
        mov     [esp+MUTEX_WAITER.type], 2; RWSEM_WAITING_FOR_WRITE
283
        mov     [edx+TASKDATA.state], 1
284
 
285
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
286
 
287
        xor     eax, eax
288
        not     eax
289
 
290
.forever:
291
        test    eax, [ecx+RWSEM.count]
292
        jz      @F
293
 
294
        mov     [edx+TASKDATA.state], 1
295
        call    change_task
296
        jmp     .forever
297
@@:
298
        mov     [ecx+RWSEM.count], eax
299
        list_del esp
300
 
301
        add     esp, sizeof.MUTEX_WAITER
302
        popfd
303
        ret
304
 
2288 clevermous 305
purge MUTEX_WAITER
306
 
3534 clevermous 307
MAX_PRIORITY      = 0   ; highest, used for kernel tasks
308
USER_PRIORITY     = 1   ; default
309
IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
310
NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
311
 
312
uglobal
313
; [scheduler_current + i*4] = zero if there are no threads with priority i,
314
;  pointer to APPDATA of the current thread with priority i otherwise.
315
align 4
316
scheduler_current       rd      NR_SCHED_QUEUES
317
endg
318
 
319
; Add the given thread to the given priority list for the scheduler.
320
; in: edx -> APPDATA, ecx = priority
321
proc scheduler_add_thread
322
; 1. Acquire the lock.
323
        spin_lock_irqsave SchedulerLock
324
; 2. Store the priority in APPDATA structure.
325
        mov     [edx+APPDATA.priority], ecx
326
; 3. There are two different cases: the given list is empty or not empty.
327
; In first case, go to 6. Otherwise, advance to 4.
328
        mov     eax, [scheduler_current+ecx*4]
329
        test    eax, eax
330
        jz      .new_list
331
; 4. Insert the new item immediately before the current item.
332
        mov     ecx, [eax+APPDATA.in_schedule.prev]
333
        mov     [edx+APPDATA.in_schedule.next], eax
334
        mov     [edx+APPDATA.in_schedule.prev], ecx
335
        mov     [eax+APPDATA.in_schedule.prev], edx
336
        mov     [ecx+APPDATA.in_schedule.next], edx
337
; 5. Release the lock and return.
338
        spin_unlock_irqrestore SchedulerLock
339
        ret
340
.new_list:
341
; 6. Initialize the list with one item and make it the current item.
342
        mov     [edx+APPDATA.in_schedule.next], edx
343
        mov     [edx+APPDATA.in_schedule.prev], edx
344
        mov     [scheduler_current+ecx*4], edx
345
; 7. Release the lock and return.
346
        spin_unlock_irqrestore SchedulerLock
347
        ret
348
endp
349
 
350
; Remove the given thread from the corresponding priority list for the scheduler.
351
; in: edx -> APPDATA
352
proc scheduler_remove_thread
353
; 1. Acquire the lock.
354
        spin_lock_irqsave SchedulerLock
355
; 2. Remove the item from the corresponding list.
356
        mov     eax, [edx+APPDATA.in_schedule.next]
357
        mov     ecx, [edx+APPDATA.in_schedule.prev]
358
        mov     [eax+APPDATA.in_schedule.prev], ecx
359
        mov     [ecx+APPDATA.in_schedule.next], eax
360
; 3. If the given thread is the current item in the list,
361
; advance the current item.
362
; 3a. Check whether the given thread is the current item;
363
; if no, skip the rest of this step.
364
        mov     ecx, [edx+APPDATA.priority]
365
        cmp     [scheduler_current+ecx*4], edx
366
        jnz     .return
367
; 3b. Set the current item to eax; step 2 has set eax = next item.
368
        mov     [scheduler_current+ecx*4], eax
369
; 3c. If there were only one item in the list, zero the current item.
370
        cmp     eax, edx
371
        jnz     .return
372
        mov     [scheduler_current+ecx*4], 0
373
.return:
374
; 4. Release the lock and return.
375
        spin_unlock_irqrestore SchedulerLock
376
        ret
377
endp
378
 
3615 clevermous 379
SCHEDULE_ANY_PRIORITY = 0
380
SCHEDULE_HIGHER_PRIORITY = 1
3534 clevermous 381
;info:
382
;   Find next task to execute
3615 clevermous 383
;in:
384
;   bl = SCHEDULE_ANY_PRIORITY:
385
;        consider threads with any priority
386
;   bl = SCHEDULE_HIGHER_PRIORITY:
387
;        consider only threads with strictly higher priority than the current one,
388
;        keep running the current thread if other ready threads have the same or lower priority
3534 clevermous 389
;retval:
390
;   ebx = address of the APPDATA for the selected task (slot-base)
391
;   edi = address of the TASKDATA for the selected task
392
;   ZF  = 1  if the task is the same
393
;warning:
394
;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
395
;   [current_slot] is not set to new value (ebx)!!!
396
;scratched: eax,ecx
397
proc find_next_task
398
        call    update_counters
399
        spin_lock_irqsave SchedulerLock
3615 clevermous 400
        push    NR_SCHED_QUEUES
401
; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
402
; Otherwise, loop over first [APPDATA.priority] lists.
403
        test    bl, bl
404
        jz      .start
405
        mov     ebx, [current_slot]
406
        mov     edi, [TASK_BASE]
407
        mov     eax, [ebx+APPDATA.priority]
408
        test    eax, eax
409
        jz      .unlock_found
410
        mov     [esp], eax
411
.start:
3534 clevermous 412
        xor     ecx, ecx
413
.priority_loop:
414
        mov     ebx, [scheduler_current+ecx*4]
415
        test    ebx, ebx
416
        jz      .priority_next
417
.task_loop:
418
        mov     ebx, [ebx+APPDATA.in_schedule.next]
419
        mov     edi, ebx
420
        shr     edi, 3
421
        add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
422
        mov     al, [edi+TASKDATA.state]
423
        test    al, al
424
        jz      .task_found     ; state == 0
425
        cmp     al, 5
426
        jne     .task_next      ; state == 1,2,3,4,9
427
      ; state == 5
428
        pushad  ; more freedom for [APPDATA.wait_test]
429
        call    [ebx+APPDATA.wait_test]
430
        mov     [esp+28], eax
431
        popad
432
        or      eax, eax
433
        jnz     @f
434
      ; testing for timeout
435
        mov     eax, [timer_ticks]
436
        sub     eax, [ebx+APPDATA.wait_begin]
437
        cmp     eax, [ebx+APPDATA.wait_timeout]
438
        jb      .task_next
439
        xor     eax, eax
440
@@:
441
        mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
442
        mov     [edi+TASKDATA.state], 0
443
.task_found:
444
        mov     [scheduler_current+ecx*4], ebx
3617 clevermous 445
; If we have selected a thread with higher priority
446
; AND rescheduling is due to IRQ,
447
; turn the current scheduler list one entry back,
448
; so the current thread will be next after high-priority thread is done.
449
        mov     ecx, [esp]
450
        cmp     ecx, NR_SCHED_QUEUES
451
        jz      .unlock_found
452
        mov     eax, [current_slot]
453
        mov     eax, [eax+APPDATA.in_schedule.prev]
454
        mov     [scheduler_current+ecx*4], eax
3615 clevermous 455
.unlock_found:
456
        pop     ecx
3534 clevermous 457
        spin_unlock_irqrestore SchedulerLock
458
.found:
459
        mov     [CURRENT_TASK], bh
460
        mov     [TASK_BASE], edi
461
        rdtsc   ;call  _rdtsc
462
        mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
463
        cmp     ebx, [current_slot]
464
        ret
465
.task_next:
466
        cmp     ebx, [scheduler_current+ecx*4]
467
        jnz     .task_loop
468
.priority_next:
469
        inc     ecx
3615 clevermous 470
        cmp     ecx, [esp]
3534 clevermous 471
        jb      .priority_loop
3615 clevermous 472
        mov     ebx, [current_slot]
473
        mov     edi, [TASK_BASE]
474
        jmp     .unlock_found
3534 clevermous 475
endp
476
 
2288 clevermous 477
if 0
478
 
479
struc TIMER
480
{
481
  .next      dd ?
482
  .exp_time  dd ?
483
  .func      dd ?
484
  .arg       dd ?
485
}
486
 
487
 
488
uglobal
489
rdy_head   rd 16
490
endg
491
 
492
align 4
493
pick_task:
494
 
495
        xor     eax, eax
496
  .pick:
497
        mov     ebx, [rdy_head+eax*4]
498
        test    ebx, ebx
499
        jz      .next
500
 
501
        mov     [next_task], ebx
502
        test    [ebx+flags.billable]
503
        jz      @F
504
        mov     [bill_task], ebx
505
  @@:
506
        ret
507
  .next:
508
        inc     eax
509
        jmp     .pick
510
 
511
; param
512
;  eax= task
513
;
514
; retval
515
;  eax= task
516
;  ebx= queue
517
;  ecx= front if 1 or back if 0
518
align 4
519
shed:
520
        cmp     [eax+.tics_left], 0;signed compare
521
        mov     ebx, [eax+.priority]
522
        setg    ecx
523
        jg      @F
524
 
525
        mov     edx, [eax+.tics_quantum]
526
        mov     [eax+.ticks_left], edx
527
        cmp     ebx, (IDLE_PRIORITY-1)
528
        je      @F
529
        inc     ebx
530
  @@:
531
        ret
532
 
533
; param
534
;  eax= task
535
align 4
536
enqueue:
537
        call    shed;eax
538
        cmp     [rdy_head+ebx*4], 0
539
        jnz     @F
540
 
541
        mov     [rdy_head+ebx*4], eax
542
        mov     [rdy_tail+ebx*4], eax
543
        mov     [eax+.next_ready], 0
544
        jmp     .pick
545
  @@:
546
        test    ecx, ecx
547
        jz      .back
548
 
549
        mov     ecx, [rdy_head+ebx*4]
550
        mov     [eax+.next_ready], ecx
551
        mov     [rdy_head+ebx*4], eax
552
        jmp     .pick
553
  .back:
554
        mov     ecx, [rdy_tail+ebx*4]
555
        mov     [ecx+.next_ready], eax
556
        mov     [rdy_tail+ebx*4], eax
557
        mov     [eax+.next_ready], 0
558
  .pick:
559
        call    pick_proc;select next task
560
        ret
561
 
562
end if