Subversion Repositories Kolibri OS

Rev

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