Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
431 serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
5565 serge 3
;; Copyright (C) KolibriOS team 2004-2015. 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: 5565 $
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]
1220 serge 119
 
2434 Serge 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
1220 serge 124
 
2434 Serge 125
        mov     dx, app_tls
126
        mov     fs, dx
5565 serge 127
 
1220 serge 128
; set gs selector unconditionally
1055 Galkov 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
5201 serge 144
        lea     esi, [ebx+APPDATA.dbg_regs]
1055 Galkov 145
        cld
146
  macro lodsReg [reg] {
147
        lodsd
2434 Serge 148
        mov     reg, eax
1055 Galkov 149
  }     lodsReg dr0, dr1, dr2, dr3, dr7
150
  purge lodsReg
2434 Serge 151
  @@:
152
        ret
1055 Galkov 153
;end.
465 serge 154
 
1434 serge 155
 
2434 Serge 156
struct  MUTEX_WAITER
157
        list    LHEAD
158
        task    dd ?
5565 serge 159
        type    dd ?
2434 Serge 160
ends
1434 serge 161
 
5565 serge 162
RWSEM_WAITING_FOR_WRITE equ 0
163
RWSEM_WAITING_FOR_READ  equ 1
164
 
1434 serge 165
;void  __fastcall mutex_init(struct mutex *lock)
166
 
167
align 4
168
mutex_init:
5565 serge 169
        mov     [ecx+MUTEX.wait_list.next], ecx
170
        mov     [ecx+MUTEX.wait_list.prev], ecx
2434 Serge 171
        mov     [ecx+MUTEX.count], 1
1434 serge 172
        ret
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
@@:
5565 serge 203
        mov     eax, ecx
204
        list_del esp
1434 serge 205
 
5565 serge 206
        cmp     [eax+MUTEX.wait_list.next], eax
2434 Serge 207
        jne     @F
1434 serge 208
 
5565 serge 209
        mov     [eax+MUTEX.count], 0
1434 serge 210
@@:
2434 Serge 211
        add     esp, sizeof.MUTEX_WAITER
1434 serge 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
 
5565 serge 225
        mov     eax, [ecx+MUTEX.wait_list.next]
2434 Serge 226
        cmp     eax, ecx
227
        mov     [ecx+MUTEX.count], 1
228
        je      @F
1434 serge 229
 
2434 Serge 230
        mov     eax, [eax+MUTEX_WAITER.task]
231
        mov     [eax+TASKDATA.state], 0
1434 serge 232
@@:
233
        popfd
234
        ret
235
 
236
 
5565 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
 
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
264
        mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
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
291
        mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
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
 
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
 
1434 serge 393
purge MUTEX_WAITER
5565 serge 394
purge RWSEM_WAITING_FOR_WRITE
395
purge RWSEM_WAITING_FOR_READ
1434 serge 396
 
5565 serge 397
 
3555 Serge 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
 
3626 Serge 470
SCHEDULE_ANY_PRIORITY = 0
471
SCHEDULE_HIGHER_PRIORITY = 1
3555 Serge 472
;info:
473
;   Find next task to execute
3626 Serge 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
3555 Serge 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
3626 Serge 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:
3555 Serge 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
3626 Serge 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
546
.unlock_found:
547
        pop     ecx
3555 Serge 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
3626 Serge 561
        cmp     ecx, [esp]
3555 Serge 562
        jb      .priority_loop
3626 Serge 563
        mov     ebx, [current_slot]
564
        mov     edi, [TASK_BASE]
565
        jmp     .unlock_found
3555 Serge 566
endp
567
 
465 serge 568
if 0
1434 serge 569
 
465 serge 570
struc TIMER
571
{
572
  .next      dd ?
573
  .exp_time  dd ?
574
  .func      dd ?
1055 Galkov 575
  .arg       dd ?
465 serge 576
}
577
 
1276 Lrz 578
 
579
uglobal
465 serge 580
rdy_head   rd 16
1276 Lrz 581
endg
465 serge 582
 
583
align 4
584
pick_task:
585
 
2434 Serge 586
        xor     eax, eax
1055 Galkov 587
  .pick:
2434 Serge 588
        mov     ebx, [rdy_head+eax*4]
589
        test    ebx, ebx
590
        jz      .next
465 serge 591
 
2434 Serge 592
        mov     [next_task], ebx
593
        test    [ebx+flags.billable]
594
        jz      @F
595
        mov     [bill_task], ebx
1055 Galkov 596
  @@:
2434 Serge 597
        ret
1055 Galkov 598
  .next:
2434 Serge 599
        inc     eax
600
        jmp     .pick
465 serge 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:
2434 Serge 611
        cmp     [eax+.tics_left], 0;signed compare
612
        mov     ebx, [eax+.priority]
613
        setg    ecx
614
        jg      @F
465 serge 615
 
2434 Serge 616
        mov     edx, [eax+.tics_quantum]
617
        mov     [eax+.ticks_left], edx
618
        cmp     ebx, (IDLE_PRIORITY-1)
619
        je      @F
620
        inc     ebx
1055 Galkov 621
  @@:
2434 Serge 622
        ret
465 serge 623
 
624
; param
625
;  eax= task
626
align 4
627
enqueue:
2434 Serge 628
        call    shed;eax
629
        cmp     [rdy_head+ebx*4], 0
630
        jnz     @F
465 serge 631
 
2434 Serge 632
        mov     [rdy_head+ebx*4], eax
633
        mov     [rdy_tail+ebx*4], eax
634
        mov     [eax+.next_ready], 0
635
        jmp     .pick
1055 Galkov 636
  @@:
2434 Serge 637
        test    ecx, ecx
638
        jz      .back
465 serge 639
 
2434 Serge 640
        mov     ecx, [rdy_head+ebx*4]
641
        mov     [eax+.next_ready], ecx
642
        mov     [rdy_head+ebx*4], eax
643
        jmp     .pick
1055 Galkov 644
  .back:
2434 Serge 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
1055 Galkov 649
  .pick:
2434 Serge 650
        call    pick_proc;select next task
651
        ret
465 serge 652
 
653
end if