Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
2288 clevermous 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2004-2015. 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: 5376 $
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
 
120
        mov     [tls_data_l+2], dx
121
        shr     edx, 16
122
        mov     [tls_data_l+4], dl
123
        mov     [tls_data_l+7], dh
124
 
125
        mov     dx, app_tls
126
        mov     fs, dx
5376 serge 127
 
2288 clevermous 128
; set gs selector unconditionally
129
        Mov     gs,ax,graph_data
130
      ; set CR0.TS
131
        cmp     bh, byte[fpu_owner] ;bh == incoming task (new)
132
        clts                        ;clear a task switch flag
133
        je      @f
134
        mov     eax, cr0            ;and set it again if the owner
135
        or      eax, CR0_TS         ;of a fpu has changed
136
        mov     cr0, eax
137
  @@: ; set context_counter (only for user pleasure ???)
138
        inc     [context_counter]   ;noname & halyavin
139
      ; set debug-registers, if it's necessary
140
        test    byte[ebx+APPDATA.dbg_state], 1
141
        jz      @f
142
        xor     eax, eax
143
        mov     dr6, eax
5130 serge 144
        lea     esi, [ebx+APPDATA.dbg_regs]
2288 clevermous 145
        cld
146
  macro lodsReg [reg] {
147
        lodsd
148
        mov     reg, eax
149
  }     lodsReg dr0, dr1, dr2, dr3, dr7
150
  purge lodsReg
151
  @@:
152
        ret
153
;end.
154
 
155
 
2381 hidnplayr 156
struct  MUTEX_WAITER
157
        list    LHEAD
158
        task    dd ?
5343 serge 159
        type    dd ?
2381 hidnplayr 160
ends
2288 clevermous 161
 
5344 serge 162
RWSEM_WAITING_FOR_WRITE equ 0
163
RWSEM_WAITING_FOR_READ  equ 1
164
 
2288 clevermous 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
 
5344 serge 237
;void __fastcall init_rwsem(struct rw_semaphore *sem)
238
 
239
align 4
240
init_rwsem:
241
        mov     [ecx+RWSEM.wait_list.next], ecx
242
        mov     [ecx+RWSEM.wait_list.prev], ecx
243
        mov     [ecx+RWSEM.count], 0
244
        ret
245
 
5343 serge 246
;void __fastcall down_read(struct rw_semaphore *sem)
247
 
248
align 4
249
down_read:
250
        pushfd
251
        cli
252
 
253
        mov     eax, [ecx+RWSEM.count]
254
        test    eax, eax
255
        js      @F
256
 
257
        cmp     ecx, [ecx+RWSEM.wait_list.next]
258
        je      .ok
259
@@:
260
        sub     esp, sizeof.MUTEX_WAITER
261
 
262
        mov     eax, [TASK_BASE]
263
        mov     [esp+MUTEX_WAITER.task], eax
5344 serge 264
        mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
5343 serge 265
        mov     [eax+TASKDATA.state], 1
266
 
267
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
268
 
269
        call    change_task
270
 
271
        add     esp, sizeof.MUTEX_WAITER
272
        popfd
273
        ret
274
.ok:
275
        inc     eax
276
        mov     [ecx+RWSEM.count], eax
277
 
278
        popfd
279
        ret
280
 
281
;void __fastcall down_write(struct rw_semaphore *sem)
282
 
283
align 4
284
down_write:
285
        pushfd
286
        cli
287
        sub     esp, sizeof.MUTEX_WAITER
288
 
289
        mov     edx, [TASK_BASE]
290
        mov     [esp+MUTEX_WAITER.task], edx
5344 serge 291
        mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
5343 serge 292
        mov     [edx+TASKDATA.state], 1
293
 
294
        list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
295
 
296
        xor     eax, eax
297
        not     eax
298
 
299
.forever:
300
        test    eax, [ecx+RWSEM.count]
301
        jz      @F
302
 
303
        mov     [edx+TASKDATA.state], 1
304
        call    change_task
305
        jmp     .forever
306
@@:
307
        mov     [ecx+RWSEM.count], eax
308
        list_del esp
309
 
310
        add     esp, sizeof.MUTEX_WAITER
311
        popfd
312
        ret
313
 
5344 serge 314
;void __fastcall up_read(struct rw_semaphore *sem)
315
 
316
align 4
317
up_read:
318
        pushfd
319
        cli
320
 
321
        dec     [ecx+RWSEM.count]
322
        jnz     @F
323
 
324
        mov     eax, [ecx+RWSEM.wait_list.next]
325
        cmp     eax, ecx
326
        je      @F
327
 
328
        mov     eax, [eax+MUTEX_WAITER.task]
329
        mov     [eax+TASKDATA.state], 0
330
@@:
331
        popfd
332
        ret
333
 
334
;void __fastcall up_write(struct rw_semaphore *sem)
335
 
336
align 4
337
up_write:
338
 
339
        pushfd
340
        cli
341
 
342
        mov     eax, [ecx+RWSEM.wait_list.next]
343
        mov     [ecx+RWSEM.count], 0
344
 
345
        cmp     ecx, eax
346
        je      .done
347
 
348
        mov     edx, [eax+MUTEX_WAITER.type]
349
        test    edx, edx
350
        jnz     .wake
351
 
352
        mov     eax, [eax+MUTEX_WAITER.task]
353
        mov     [eax+TASKDATA.state], 0
354
.done:
355
        popfd
356
        ret
357
 
358
.wake:
359
        push    ebx
360
        push    esi
361
        push    edi
362
 
363
        xor     esi, esi
364
        mov     edi, ecx
365
 
366
.wake_list:
367
 
368
        mov     ebx, [eax+MUTEX_WAITER.list.next]
369
        list_del eax
370
        mov     edx, [eax+MUTEX_WAITER.task]
371
        mov     [edx+TASKDATA.state], 0
372
        inc     esi
373
        cmp     edi, ebx
374
        je      .wake_done
375
 
376
        mov     ecx, [ebx+MUTEX_WAITER.type]
377
        test    ecx, ecx
378
        jz      .wake_done
379
 
380
        mov     eax, ebx
381
        jmp     .wake_list
382
 
383
.wake_done:
384
        add     [edi+RWSEM.count], esi
385
 
386
        pop     edi
387
        pop     esi
388
        pop     ebx
389
        popfd
390
        ret
391
 
392
 
2288 clevermous 393
purge MUTEX_WAITER
5344 serge 394
purge RWSEM_WAITING_FOR_WRITE
395
purge RWSEM_WAITING_FOR_READ
2288 clevermous 396
 
5344 serge 397
 
3534 clevermous 398
MAX_PRIORITY      = 0   ; highest, used for kernel tasks
399
USER_PRIORITY     = 1   ; default
400
IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
401
NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
402
 
403
uglobal
404
; [scheduler_current + i*4] = zero if there are no threads with priority i,
405
;  pointer to APPDATA of the current thread with priority i otherwise.
406
align 4
407
scheduler_current       rd      NR_SCHED_QUEUES
408
endg
409
 
410
; Add the given thread to the given priority list for the scheduler.
411
; in: edx -> APPDATA, ecx = priority
412
proc scheduler_add_thread
413
; 1. Acquire the lock.
414
        spin_lock_irqsave SchedulerLock
415
; 2. Store the priority in APPDATA structure.
416
        mov     [edx+APPDATA.priority], ecx
417
; 3. There are two different cases: the given list is empty or not empty.
418
; In first case, go to 6. Otherwise, advance to 4.
419
        mov     eax, [scheduler_current+ecx*4]
420
        test    eax, eax
421
        jz      .new_list
422
; 4. Insert the new item immediately before the current item.
423
        mov     ecx, [eax+APPDATA.in_schedule.prev]
424
        mov     [edx+APPDATA.in_schedule.next], eax
425
        mov     [edx+APPDATA.in_schedule.prev], ecx
426
        mov     [eax+APPDATA.in_schedule.prev], edx
427
        mov     [ecx+APPDATA.in_schedule.next], edx
428
; 5. Release the lock and return.
429
        spin_unlock_irqrestore SchedulerLock
430
        ret
431
.new_list:
432
; 6. Initialize the list with one item and make it the current item.
433
        mov     [edx+APPDATA.in_schedule.next], edx
434
        mov     [edx+APPDATA.in_schedule.prev], edx
435
        mov     [scheduler_current+ecx*4], edx
436
; 7. Release the lock and return.
437
        spin_unlock_irqrestore SchedulerLock
438
        ret
439
endp
440
 
441
; Remove the given thread from the corresponding priority list for the scheduler.
442
; in: edx -> APPDATA
443
proc scheduler_remove_thread
444
; 1. Acquire the lock.
445
        spin_lock_irqsave SchedulerLock
446
; 2. Remove the item from the corresponding list.
447
        mov     eax, [edx+APPDATA.in_schedule.next]
448
        mov     ecx, [edx+APPDATA.in_schedule.prev]
449
        mov     [eax+APPDATA.in_schedule.prev], ecx
450
        mov     [ecx+APPDATA.in_schedule.next], eax
451
; 3. If the given thread is the current item in the list,
452
; advance the current item.
453
; 3a. Check whether the given thread is the current item;
454
; if no, skip the rest of this step.
455
        mov     ecx, [edx+APPDATA.priority]
456
        cmp     [scheduler_current+ecx*4], edx
457
        jnz     .return
458
; 3b. Set the current item to eax; step 2 has set eax = next item.
459
        mov     [scheduler_current+ecx*4], eax
460
; 3c. If there were only one item in the list, zero the current item.
461
        cmp     eax, edx
462
        jnz     .return
463
        mov     [scheduler_current+ecx*4], 0
464
.return:
465
; 4. Release the lock and return.
466
        spin_unlock_irqrestore SchedulerLock
467
        ret
468
endp
469
 
3615 clevermous 470
SCHEDULE_ANY_PRIORITY = 0
471
SCHEDULE_HIGHER_PRIORITY = 1
3534 clevermous 472
;info:
473
;   Find next task to execute
3615 clevermous 474
;in:
475
;   bl = SCHEDULE_ANY_PRIORITY:
476
;        consider threads with any priority
477
;   bl = SCHEDULE_HIGHER_PRIORITY:
478
;        consider only threads with strictly higher priority than the current one,
479
;        keep running the current thread if other ready threads have the same or lower priority
3534 clevermous 480
;retval:
481
;   ebx = address of the APPDATA for the selected task (slot-base)
482
;   edi = address of the TASKDATA for the selected task
483
;   ZF  = 1  if the task is the same
484
;warning:
485
;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
486
;   [current_slot] is not set to new value (ebx)!!!
487
;scratched: eax,ecx
488
proc find_next_task
489
        call    update_counters
490
        spin_lock_irqsave SchedulerLock
3615 clevermous 491
        push    NR_SCHED_QUEUES
492
; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
493
; Otherwise, loop over first [APPDATA.priority] lists.
494
        test    bl, bl
495
        jz      .start
496
        mov     ebx, [current_slot]
497
        mov     edi, [TASK_BASE]
498
        mov     eax, [ebx+APPDATA.priority]
499
        test    eax, eax
500
        jz      .unlock_found
501
        mov     [esp], eax
502
.start:
3534 clevermous 503
        xor     ecx, ecx
504
.priority_loop:
505
        mov     ebx, [scheduler_current+ecx*4]
506
        test    ebx, ebx
507
        jz      .priority_next
508
.task_loop:
509
        mov     ebx, [ebx+APPDATA.in_schedule.next]
510
        mov     edi, ebx
511
        shr     edi, 3
512
        add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
513
        mov     al, [edi+TASKDATA.state]
514
        test    al, al
515
        jz      .task_found     ; state == 0
516
        cmp     al, 5
517
        jne     .task_next      ; state == 1,2,3,4,9
518
      ; state == 5
519
        pushad  ; more freedom for [APPDATA.wait_test]
520
        call    [ebx+APPDATA.wait_test]
521
        mov     [esp+28], eax
522
        popad
523
        or      eax, eax
524
        jnz     @f
525
      ; testing for timeout
526
        mov     eax, [timer_ticks]
527
        sub     eax, [ebx+APPDATA.wait_begin]
528
        cmp     eax, [ebx+APPDATA.wait_timeout]
529
        jb      .task_next
530
        xor     eax, eax
531
@@:
532
        mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
533
        mov     [edi+TASKDATA.state], 0
534
.task_found:
535
        mov     [scheduler_current+ecx*4], ebx
3617 clevermous 536
; If we have selected a thread with higher priority
537
; AND rescheduling is due to IRQ,
538
; turn the current scheduler list one entry back,
539
; so the current thread will be next after high-priority thread is done.
540
        mov     ecx, [esp]
541
        cmp     ecx, NR_SCHED_QUEUES
542
        jz      .unlock_found
543
        mov     eax, [current_slot]
544
        mov     eax, [eax+APPDATA.in_schedule.prev]
545
        mov     [scheduler_current+ecx*4], eax
3615 clevermous 546
.unlock_found:
547
        pop     ecx
3534 clevermous 548
        spin_unlock_irqrestore SchedulerLock
549
.found:
550
        mov     [CURRENT_TASK], bh
551
        mov     [TASK_BASE], edi
552
        rdtsc   ;call  _rdtsc
553
        mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
554
        cmp     ebx, [current_slot]
555
        ret
556
.task_next:
557
        cmp     ebx, [scheduler_current+ecx*4]
558
        jnz     .task_loop
559
.priority_next:
560
        inc     ecx
3615 clevermous 561
        cmp     ecx, [esp]
3534 clevermous 562
        jb      .priority_loop
3615 clevermous 563
        mov     ebx, [current_slot]
564
        mov     edi, [TASK_BASE]
565
        jmp     .unlock_found
3534 clevermous 566
endp
567
 
2288 clevermous 568
if 0
569
 
570
struc TIMER
571
{
572
  .next      dd ?
573
  .exp_time  dd ?
574
  .func      dd ?
575
  .arg       dd ?
576
}
577
 
578
 
579
uglobal
580
rdy_head   rd 16
581
endg
582
 
583
align 4
584
pick_task:
585
 
586
        xor     eax, eax
587
  .pick:
588
        mov     ebx, [rdy_head+eax*4]
589
        test    ebx, ebx
590
        jz      .next
591
 
592
        mov     [next_task], ebx
593
        test    [ebx+flags.billable]
594
        jz      @F
595
        mov     [bill_task], ebx
596
  @@:
597
        ret
598
  .next:
599
        inc     eax
600
        jmp     .pick
601
 
602
; param
603
;  eax= task
604
;
605
; retval
606
;  eax= task
607
;  ebx= queue
608
;  ecx= front if 1 or back if 0
609
align 4
610
shed:
611
        cmp     [eax+.tics_left], 0;signed compare
612
        mov     ebx, [eax+.priority]
613
        setg    ecx
614
        jg      @F
615
 
616
        mov     edx, [eax+.tics_quantum]
617
        mov     [eax+.ticks_left], edx
618
        cmp     ebx, (IDLE_PRIORITY-1)
619
        je      @F
620
        inc     ebx
621
  @@:
622
        ret
623
 
624
; param
625
;  eax= task
626
align 4
627
enqueue:
628
        call    shed;eax
629
        cmp     [rdy_head+ebx*4], 0
630
        jnz     @F
631
 
632
        mov     [rdy_head+ebx*4], eax
633
        mov     [rdy_tail+ebx*4], eax
634
        mov     [eax+.next_ready], 0
635
        jmp     .pick
636
  @@:
637
        test    ecx, ecx
638
        jz      .back
639
 
640
        mov     ecx, [rdy_head+ebx*4]
641
        mov     [eax+.next_ready], ecx
642
        mov     [rdy_head+ebx*4], eax
643
        jmp     .pick
644
  .back:
645
        mov     ecx, [rdy_tail+ebx*4]
646
        mov     [ecx+.next_ready], eax
647
        mov     [rdy_tail+ebx*4], eax
648
        mov     [eax+.next_ready], 0
649
  .pick:
650
        call    pick_proc;select next task
651
        ret
652
 
653
end if