Subversion Repositories Kolibri OS

Rev

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