Subversion Repositories Kolibri OS

Rev

Rev 3617 | Rev 5130 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
  4. ;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
  5. ;; Distributed under terms of the GNU General Public License    ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 4700 $
  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
  32.  
  33.         mov     bl, SCHEDULE_ANY_PRIORITY
  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
  46.         mov     bl, SCHEDULE_ANY_PRIORITY
  47.         call    find_next_task
  48.         jz      .return  ; the same task -> skip switch
  49.  
  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.  
  87. ;TODO: Надо бы убрать использование do_change_task из V86...
  88. ; и после этого перенести обработку TASKDATA.counter_add/sum в do_change_task
  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
  107.         mov     ecx, APPDATA.dir_table
  108.         mov     eax, [ebx+ecx]      ;offset>0x7F
  109.         cmp     eax, [esi+ecx]      ;offset>0x7F
  110.         je      @f
  111.         mov     cr3, eax
  112. @@:
  113. ; set tss.esp0
  114.  
  115.         Mov     [tss._esp0],eax,[ebx+APPDATA.saved_esp0]
  116.  
  117.         mov     edx, [ebx+APPDATA.tls_base]
  118.         cmp     edx, [esi+APPDATA.tls_base]
  119.         je      @f
  120.  
  121.         mov     [tls_data_l+2], dx
  122.         shr     edx, 16
  123.         mov     [tls_data_l+4], dl
  124.         mov     [tls_data_l+7], dh
  125.  
  126.         mov     dx, app_tls
  127.         mov     fs, dx
  128. @@:
  129. ; set gs selector unconditionally
  130.         Mov     gs,ax,graph_data
  131.       ; set CR0.TS
  132.         cmp     bh, byte[fpu_owner] ;bh == incoming task (new)
  133.         clts                        ;clear a task switch flag
  134.         je      @f
  135.         mov     eax, cr0            ;and set it again if the owner
  136.         or      eax, CR0_TS         ;of a fpu has changed
  137.         mov     cr0, eax
  138.   @@: ; set context_counter (only for user pleasure ???)
  139.         inc     [context_counter]   ;noname & halyavin
  140.       ; set debug-registers, if it's necessary
  141.         test    byte[ebx+APPDATA.dbg_state], 1
  142.         jz      @f
  143.         xor     eax, eax
  144.         mov     dr6, eax
  145.         lea     esi, [ebx+ecx+APPDATA.dbg_regs-APPDATA.dir_table];offset>0x7F
  146.         cld
  147.   macro lodsReg [reg] {
  148.         lodsd
  149.         mov     reg, eax
  150.   }     lodsReg dr0, dr1, dr2, dr3, dr7
  151.   purge lodsReg
  152.   @@:
  153.         ret
  154. ;end.
  155.  
  156.  
  157.  
  158. struct  MUTEX_WAITER
  159.         list    LHEAD
  160.         task    dd ?
  161. ends
  162.  
  163. ;void  __fastcall mutex_init(struct mutex *lock)
  164.  
  165. align 4
  166. mutex_init:
  167.         mov     [ecx+MUTEX.lhead.next], ecx
  168.         mov     [ecx+MUTEX.lhead.prev], ecx
  169.         mov     [ecx+MUTEX.count], 1
  170.         ret
  171.  
  172.  
  173. ;void  __fastcall mutex_lock(struct mutex *lock)
  174.  
  175. align 4
  176. mutex_lock:
  177.  
  178.         dec     [ecx+MUTEX.count]
  179.         jns     .done
  180.  
  181.         pushfd
  182.         cli
  183.  
  184.         sub     esp, sizeof.MUTEX_WAITER
  185.  
  186.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  187.  
  188.         mov     edx, [TASK_BASE]
  189.         mov     [esp+MUTEX_WAITER.task], edx
  190.  
  191. .forever:
  192.  
  193.         mov     eax, -1
  194.         xchg    eax, [ecx+MUTEX.count]
  195.         dec     eax
  196.         jz      @F
  197.  
  198.         mov     [edx+TASKDATA.state], 1
  199.         call    change_task
  200.         jmp     .forever
  201. @@:
  202.         mov     edx, [esp+MUTEX_WAITER.list.next]
  203.         mov     eax, [esp+MUTEX_WAITER.list.prev]
  204.  
  205.         mov     [eax+MUTEX_WAITER.list.next], edx
  206.         mov     [edx+MUTEX_WAITER.list.prev], eax
  207.         cmp     [ecx+MUTEX.lhead.next], ecx
  208.         jne     @F
  209.  
  210.         mov     [ecx+MUTEX.count], 0
  211. @@:
  212.         add     esp, sizeof.MUTEX_WAITER
  213.  
  214.         popfd
  215. .done:
  216.         ret
  217.  
  218. ;void  __fastcall mutex_unlock(struct mutex *lock)
  219.  
  220. align 4
  221. mutex_unlock:
  222.  
  223.         pushfd
  224.         cli
  225.  
  226.         mov     eax, [ecx+MUTEX.lhead.next]
  227.         cmp     eax, ecx
  228.         mov     [ecx+MUTEX.count], 1
  229.         je      @F
  230.  
  231.         mov     eax, [eax+MUTEX_WAITER.task]
  232.         mov     [eax+TASKDATA.state], 0
  233. @@:
  234.         popfd
  235.         ret
  236.  
  237.  
  238. purge MUTEX_WAITER
  239.  
  240. MAX_PRIORITY      = 0   ; highest, used for kernel tasks
  241. USER_PRIORITY     = 1   ; default
  242. IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
  243. NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
  244.  
  245. uglobal
  246. ; [scheduler_current + i*4] = zero if there are no threads with priority i,
  247. ;  pointer to APPDATA of the current thread with priority i otherwise.
  248. align 4
  249. scheduler_current       rd      NR_SCHED_QUEUES
  250. endg
  251.  
  252. ; Add the given thread to the given priority list for the scheduler.
  253. ; in: edx -> APPDATA, ecx = priority
  254. proc scheduler_add_thread
  255. ; 1. Acquire the lock.
  256.         spin_lock_irqsave SchedulerLock
  257. ; 2. Store the priority in APPDATA structure.
  258.         mov     [edx+APPDATA.priority], ecx
  259. ; 3. There are two different cases: the given list is empty or not empty.
  260. ; In first case, go to 6. Otherwise, advance to 4.
  261.         mov     eax, [scheduler_current+ecx*4]
  262.         test    eax, eax
  263.         jz      .new_list
  264. ; 4. Insert the new item immediately before the current item.
  265.         mov     ecx, [eax+APPDATA.in_schedule.prev]
  266.         mov     [edx+APPDATA.in_schedule.next], eax
  267.         mov     [edx+APPDATA.in_schedule.prev], ecx
  268.         mov     [eax+APPDATA.in_schedule.prev], edx
  269.         mov     [ecx+APPDATA.in_schedule.next], edx
  270. ; 5. Release the lock and return.
  271.         spin_unlock_irqrestore SchedulerLock
  272.         ret
  273. .new_list:
  274. ; 6. Initialize the list with one item and make it the current item.
  275.         mov     [edx+APPDATA.in_schedule.next], edx
  276.         mov     [edx+APPDATA.in_schedule.prev], edx
  277.         mov     [scheduler_current+ecx*4], edx
  278. ; 7. Release the lock and return.
  279.         spin_unlock_irqrestore SchedulerLock
  280.         ret
  281. endp
  282.  
  283. ; Remove the given thread from the corresponding priority list for the scheduler.
  284. ; in: edx -> APPDATA
  285. proc scheduler_remove_thread
  286. ; 1. Acquire the lock.
  287.         spin_lock_irqsave SchedulerLock
  288. ; 2. Remove the item from the corresponding list.
  289.         mov     eax, [edx+APPDATA.in_schedule.next]
  290.         mov     ecx, [edx+APPDATA.in_schedule.prev]
  291.         mov     [eax+APPDATA.in_schedule.prev], ecx
  292.         mov     [ecx+APPDATA.in_schedule.next], eax
  293. ; 3. If the given thread is the current item in the list,
  294. ; advance the current item.
  295. ; 3a. Check whether the given thread is the current item;
  296. ; if no, skip the rest of this step.
  297.         mov     ecx, [edx+APPDATA.priority]
  298.         cmp     [scheduler_current+ecx*4], edx
  299.         jnz     .return
  300. ; 3b. Set the current item to eax; step 2 has set eax = next item.
  301.         mov     [scheduler_current+ecx*4], eax
  302. ; 3c. If there were only one item in the list, zero the current item.
  303.         cmp     eax, edx
  304.         jnz     .return
  305.         mov     [scheduler_current+ecx*4], 0
  306. .return:
  307. ; 4. Release the lock and return.
  308.         spin_unlock_irqrestore SchedulerLock
  309.         ret
  310. endp
  311.  
  312. SCHEDULE_ANY_PRIORITY = 0
  313. SCHEDULE_HIGHER_PRIORITY = 1
  314. ;info:
  315. ;   Find next task to execute
  316. ;in:
  317. ;   bl = SCHEDULE_ANY_PRIORITY:
  318. ;        consider threads with any priority
  319. ;   bl = SCHEDULE_HIGHER_PRIORITY:
  320. ;        consider only threads with strictly higher priority than the current one,
  321. ;        keep running the current thread if other ready threads have the same or lower priority
  322. ;retval:
  323. ;   ebx = address of the APPDATA for the selected task (slot-base)
  324. ;   edi = address of the TASKDATA for the selected task
  325. ;   ZF  = 1  if the task is the same
  326. ;warning:
  327. ;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
  328. ;   [current_slot] is not set to new value (ebx)!!!
  329. ;scratched: eax,ecx
  330. proc find_next_task
  331.         call    update_counters
  332.         spin_lock_irqsave SchedulerLock
  333.         push    NR_SCHED_QUEUES
  334. ; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
  335. ; Otherwise, loop over first [APPDATA.priority] lists.
  336.         test    bl, bl
  337.         jz      .start
  338.         mov     ebx, [current_slot]
  339.         mov     edi, [TASK_BASE]
  340.         mov     eax, [ebx+APPDATA.priority]
  341.         test    eax, eax
  342.         jz      .unlock_found
  343.         mov     [esp], eax
  344. .start:
  345.         xor     ecx, ecx
  346. .priority_loop:
  347.         mov     ebx, [scheduler_current+ecx*4]
  348.         test    ebx, ebx
  349.         jz      .priority_next
  350. .task_loop:
  351.         mov     ebx, [ebx+APPDATA.in_schedule.next]
  352.         mov     edi, ebx
  353.         shr     edi, 3
  354.         add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
  355.         mov     al, [edi+TASKDATA.state]
  356.         test    al, al
  357.         jz      .task_found     ; state == 0
  358.         cmp     al, 5
  359.         jne     .task_next      ; state == 1,2,3,4,9
  360.       ; state == 5
  361.         pushad  ; more freedom for [APPDATA.wait_test]
  362.         call    [ebx+APPDATA.wait_test]
  363.         mov     [esp+28], eax
  364.         popad
  365.         or      eax, eax
  366.         jnz     @f
  367.       ; testing for timeout
  368.         mov     eax, [timer_ticks]
  369.         sub     eax, [ebx+APPDATA.wait_begin]
  370.         cmp     eax, [ebx+APPDATA.wait_timeout]
  371.         jb      .task_next
  372.         xor     eax, eax
  373. @@:
  374.         mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
  375.         mov     [edi+TASKDATA.state], 0
  376. .task_found:
  377.         mov     [scheduler_current+ecx*4], ebx
  378. ; If we have selected a thread with higher priority
  379. ; AND rescheduling is due to IRQ,
  380. ; turn the current scheduler list one entry back,
  381. ; so the current thread will be next after high-priority thread is done.
  382.         mov     ecx, [esp]
  383.         cmp     ecx, NR_SCHED_QUEUES
  384.         jz      .unlock_found
  385.         mov     eax, [current_slot]
  386.         mov     eax, [eax+APPDATA.in_schedule.prev]
  387.         mov     [scheduler_current+ecx*4], eax
  388. .unlock_found:
  389.         pop     ecx
  390.         spin_unlock_irqrestore SchedulerLock
  391. .found:
  392.         mov     [CURRENT_TASK], bh
  393.         mov     [TASK_BASE], edi
  394.         rdtsc   ;call  _rdtsc
  395.         mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
  396.         cmp     ebx, [current_slot]
  397.         ret
  398. .task_next:
  399.         cmp     ebx, [scheduler_current+ecx*4]
  400.         jnz     .task_loop
  401. .priority_next:
  402.         inc     ecx
  403.         cmp     ecx, [esp]
  404.         jb      .priority_loop
  405.         mov     ebx, [current_slot]
  406.         mov     edi, [TASK_BASE]
  407.         jmp     .unlock_found
  408. endp
  409.  
  410. if 0
  411.  
  412. struc TIMER
  413. {
  414.   .next      dd ?
  415.   .exp_time  dd ?
  416.   .func      dd ?
  417.   .arg       dd ?
  418. }
  419.  
  420.  
  421. uglobal
  422. rdy_head   rd 16
  423. endg
  424.  
  425. align 4
  426. pick_task:
  427.  
  428.         xor     eax, eax
  429.   .pick:
  430.         mov     ebx, [rdy_head+eax*4]
  431.         test    ebx, ebx
  432.         jz      .next
  433.  
  434.         mov     [next_task], ebx
  435.         test    [ebx+flags.billable]
  436.         jz      @F
  437.         mov     [bill_task], ebx
  438.   @@:
  439.         ret
  440.   .next:
  441.         inc     eax
  442.         jmp     .pick
  443.  
  444. ; param
  445. ;  eax= task
  446. ;
  447. ; retval
  448. ;  eax= task
  449. ;  ebx= queue
  450. ;  ecx= front if 1 or back if 0
  451. align 4
  452. shed:
  453.         cmp     [eax+.tics_left], 0;signed compare
  454.         mov     ebx, [eax+.priority]
  455.         setg    ecx
  456.         jg      @F
  457.  
  458.         mov     edx, [eax+.tics_quantum]
  459.         mov     [eax+.ticks_left], edx
  460.         cmp     ebx, (IDLE_PRIORITY-1)
  461.         je      @F
  462.         inc     ebx
  463.   @@:
  464.         ret
  465.  
  466. ; param
  467. ;  eax= task
  468. align 4
  469. enqueue:
  470.         call    shed;eax
  471.         cmp     [rdy_head+ebx*4], 0
  472.         jnz     @F
  473.  
  474.         mov     [rdy_head+ebx*4], eax
  475.         mov     [rdy_tail+ebx*4], eax
  476.         mov     [eax+.next_ready], 0
  477.         jmp     .pick
  478.   @@:
  479.         test    ecx, ecx
  480.         jz      .back
  481.  
  482.         mov     ecx, [rdy_head+ebx*4]
  483.         mov     [eax+.next_ready], ecx
  484.         mov     [rdy_head+ebx*4], eax
  485.         jmp     .pick
  486.   .back:
  487.         mov     ecx, [rdy_tail+ebx*4]
  488.         mov     [ecx+.next_ready], eax
  489.         mov     [rdy_tail+ebx*4], eax
  490.         mov     [eax+.next_ready], 0
  491.   .pick:
  492.         call    pick_proc;select next task
  493.         ret
  494.  
  495. end if
  496.