Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;; Synhronization for MenuetOS.                                 ;;
  7. ;; Author: Halyavin Andrey, halyavin@land.ru                    ;;
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  9.  
  10. $Revision: 5605 $
  11.  
  12. align 4
  13. ;struct futex*  __fastcall create_futex(int *ptr)
  14. create_futex:
  15.         push    ecx
  16.         mov     ecx, sizeof.FUTEX
  17.         call    create_object
  18.         pop     ecx
  19.         test    eax, eax
  20.         jz .fail
  21.  
  22.         mov     [eax+FUTEX.magic], 'FUTX'
  23.         mov     [eax+FUTEX.destroy], 0
  24.         mov     [eax+FUTEX.pointer], ecx
  25.         lea     ecx, [eax+FUTEX.wait_list]
  26.         list_init ecx
  27.         mov     [eax+FUTEX.flags], 0
  28. .fail:
  29.         ret
  30.  
  31. align 4
  32. ;int __fastcall destroy_futex(struct futex *futex)
  33. destroy_futex:
  34.         push    esi
  35.         mov     esi, [current_process]
  36.         mov     edx, [ecx+FUTEX.handle]
  37.  
  38.         pushfd
  39.         cli
  40.  
  41.         lea     eax, [ecx+FUTEX.wait_list]
  42.         cmp     eax, [eax+LHEAD.next]
  43.         jne     .fail
  44.  
  45.         mov     eax, [esi+PROC.ht_next]
  46.         mov     [esi+PROC.htab+edx*4], eax
  47.         mov     [esi+PROC.ht_next], edx
  48.         inc     [esi+PROC.ht_free]
  49.  
  50.         popfd
  51.         pop     esi
  52.  
  53.         mov     eax, ecx
  54.         call    free
  55.         xor     eax, eax
  56.         ret
  57.  
  58. .fail:
  59.         popfd
  60.         pop     esi
  61.         mov     eax, -1
  62.         ret
  63.  
  64.  
  65. iglobal
  66. align 4
  67. f77call:
  68.         dd f77.futex_init     ;0
  69.         dd f77.futex_destroy  ;1
  70.         dd f77.futex_wait     ;2
  71.         dd f77.futex_wake     ;3
  72. .end:
  73. endg
  74.  
  75. align 4
  76. sys_synchronization:
  77. f77:
  78.         test    ebx, ebx
  79.         jz      .futex_init
  80.  
  81.         cmp     ebx, (f77call.end-f77call)/4
  82.         jae     .fail
  83.  
  84.         cmp     ecx, STDERR_FILENO
  85.         jbe     .fail
  86.         cmp     ecx, (PROC.pdt_0 - PROC.htab)/4
  87.         jae     .fail
  88.  
  89.         mov     edi, [current_process]
  90.         mov     ebp, [edi+PROC.htab+ecx*4]
  91.  
  92.         cmp     [ebp+FUTEX.magic], 'FUTX'
  93.         jne     .fail
  94.         cmp     [ebp+FUTEX.handle], ecx
  95.         jne     .fail
  96.  
  97.         jmp     dword [f77call+ebx*4]
  98.  
  99. .fail:
  100.         mov     [esp+SYSCALL_STACK._eax], -1
  101.         ret
  102.  
  103. align 4
  104. .futex_init:
  105.         call    create_futex
  106.         test    eax, eax
  107.         jz      @F
  108.         mov     eax, [eax+FUTEX.handle]
  109. @@:
  110.         mov     [esp+SYSCALL_STACK._eax], eax
  111.         ret
  112.  
  113.  
  114. align 4
  115. ;ecx futex handle
  116. ;edi current process
  117. ;ebp futex object
  118. .futex_destroy:
  119.         mov     ecx, ebp
  120.         call    destroy_futex
  121.         mov     [esp+SYSCALL_STACK._eax], eax
  122.         ret
  123.  
  124. align 4
  125. ;ecx futex handle
  126. ;edx control value
  127. ;esi timeout
  128. ;edi current process
  129. ;ebp futex object
  130. .futex_wait:
  131.         test    esi, esi
  132.         jnz     .futex_wait_timeout
  133.         mov     ecx, [ebp+FUTEX.pointer]
  134.         mov     eax, edx
  135.         lock cmpxchg [ecx], edx         ;wait until old_value == new_value
  136.         jz .wait_slow
  137.  
  138.         mov     [esp+SYSCALL_STACK._eax], 0
  139.         ret
  140.  
  141. .wait_slow:
  142.         pushfd
  143.         cli
  144.  
  145.         sub     esp, sizeof.MUTEX_WAITER
  146.         mov     ebx, [TASK_BASE]
  147.         mov     [ebx+TASKDATA.state], 1
  148.         mov     [esp+MUTEX_WAITER.task], ebx
  149.         lea     esi, [ebp+FUTEX.wait_list]
  150.  
  151.         list_add_tail esp, esi      ;esp= new waiter, esi= list head
  152.  
  153. .again:
  154.         call    change_task
  155.  
  156.         lock cmpxchg [ecx], edx
  157.         jz .again
  158.  
  159.         list_del esp
  160.         add     esp, sizeof.MUTEX_WAITER
  161.  
  162.         popfd
  163.         mov     [esp+SYSCALL_STACK._eax], 0
  164.         ret
  165.  
  166. align 4
  167. ;ecx futex handle
  168. ;edx control value
  169. ;esi timeout
  170. ;edi current process
  171. ;ebp futex object
  172.  
  173. .futex_wait_timeout:
  174.         mov     ecx, [ebp+FUTEX.pointer]
  175.         mov     eax, edx
  176.         lock cmpxchg [ecx], edx         ;wait until old_value == new_value
  177.         jz .wait_slow_timeout
  178.  
  179.         mov     [esp+SYSCALL_STACK._eax], 0
  180.         ret
  181.  
  182. align 4
  183. .wait_test:
  184.         xor     eax, eax
  185.         ret
  186.  
  187. .wait_slow_timeout:
  188.         pushfd
  189.         cli
  190.  
  191.         sub     esp, sizeof.MUTEX_WAITER
  192.  
  193.         mov     ebx, [current_slot]
  194.         mov     [ebx+APPDATA.wait_test], f77.wait_test
  195.         mov     [ebx+APPDATA.wait_timeout], esi
  196.         mov     [ebx+APPDATA.wait_param], ebp
  197.         mov     eax, [timer_ticks]
  198.         mov     [ebx+APPDATA.wait_begin], eax
  199.         mov     eax, [TASK_BASE]
  200.         mov     [eax+TASKDATA.state], 5
  201.  
  202.         mov     [esp+MUTEX_WAITER.task], ebx
  203.         lea     esi, [ebp+FUTEX.wait_list]
  204.  
  205.         list_add_tail esp, esi      ;esp= new waiter, esi= list head
  206.  
  207. .again_timeout:
  208.         call    change_task
  209.         mov     eax, [ebx+APPDATA.wait_param]
  210.         test    eax, eax
  211.         jz      .timeout
  212.  
  213.         lock cmpxchg [ecx], edx
  214.         jz .again_timeout
  215. @@:
  216.         list_del esp
  217.         add     esp, sizeof.MUTEX_WAITER
  218.  
  219.         popfd
  220.         mov     [esp+SYSCALL_STACK._eax], 0
  221.         ret
  222.  
  223. .timeout:
  224.         list_del esp
  225.         add     esp, sizeof.MUTEX_WAITER
  226.  
  227.         popfd
  228.         mov     [esp+SYSCALL_STACK._eax], -1
  229.         ret
  230.  
  231.  
  232. align 4
  233. ;ecx futex handle
  234. ;edx numder of threads
  235. ;edi current process
  236. ;ebp futex object
  237. .futex_wake:
  238.  
  239.         xor     ecx, ecx
  240.  
  241.         pushfd
  242.         cli
  243.  
  244.         lea     ebx, [ebp+FUTEX.wait_list]
  245.         mov     esi, [ebx+LHEAD.next]
  246. .wake:
  247.         cmp     esi, ebx
  248.         je      .done
  249.  
  250.         mov     eax, [esi+MUTEX_WAITER.task]
  251.         mov     [eax+TASKDATA.state], 0
  252.  
  253.         mov     esi, [esi+MUTEX_WAITER.list.next]
  254.         inc     ecx
  255.         cmp     ecx, edx
  256.         jb      .wake
  257. .done:
  258.         popfd
  259.         mov     [esp+SYSCALL_STACK._eax], ecx
  260.         ret
  261.  
  262. RWSEM_WAITING_FOR_WRITE equ 0
  263. RWSEM_WAITING_FOR_READ  equ 1
  264.  
  265. ;void  __fastcall mutex_init(struct mutex *lock)
  266.  
  267. align 4
  268. mutex_init:
  269.         mov     [ecx+MUTEX.wait_list.next], ecx
  270.         mov     [ecx+MUTEX.wait_list.prev], ecx
  271.         mov     [ecx+MUTEX.count], 1
  272.         ret
  273.  
  274. ;void  __fastcall mutex_lock(struct mutex *lock)
  275.  
  276. align 4
  277. mutex_lock:
  278.  
  279.         dec     [ecx+MUTEX.count]
  280.         jns     .done
  281.  
  282.         pushfd
  283.         cli
  284.  
  285.         sub     esp, sizeof.MUTEX_WAITER
  286.  
  287.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  288.  
  289.         mov     edx, [TASK_BASE]
  290.         mov     [esp+MUTEX_WAITER.task], edx
  291.  
  292. .forever:
  293.  
  294.         mov     eax, -1
  295.         xchg    eax, [ecx+MUTEX.count]
  296.         dec     eax
  297.         jz      @F
  298.  
  299.         mov     [edx+TASKDATA.state], 1
  300.         call    change_task
  301.         jmp     .forever
  302. @@:
  303.         mov     eax, ecx
  304.         list_del esp
  305.  
  306.         cmp     [eax+MUTEX.wait_list.next], eax
  307.         jne     @F
  308.  
  309.         mov     [eax+MUTEX.count], 0
  310. @@:
  311.         add     esp, sizeof.MUTEX_WAITER
  312.  
  313.         popfd
  314. .done:
  315.         ret
  316.  
  317. ;void  __fastcall mutex_unlock(struct mutex *lock)
  318.  
  319. align 4
  320. mutex_unlock:
  321.  
  322.         pushfd
  323.         cli
  324.  
  325.         mov     eax, [ecx+MUTEX.wait_list.next]
  326.         cmp     eax, ecx
  327.         mov     [ecx+MUTEX.count], 1
  328.         je      @F
  329.  
  330.         mov     eax, [eax+MUTEX_WAITER.task]
  331.         mov     [eax+TASKDATA.state], 0
  332. @@:
  333.         popfd
  334.         ret
  335.  
  336.  
  337. ;void __fastcall init_rwsem(struct rw_semaphore *sem)
  338.  
  339. align 4
  340. init_rwsem:
  341.         mov     [ecx+RWSEM.wait_list.next], ecx
  342.         mov     [ecx+RWSEM.wait_list.prev], ecx
  343.         mov     [ecx+RWSEM.count], 0
  344.         ret
  345.  
  346. ;void __fastcall down_read(struct rw_semaphore *sem)
  347.  
  348. align 4
  349. down_read:
  350.         pushfd
  351.         cli
  352.  
  353.         mov     eax, [ecx+RWSEM.count]
  354.         test    eax, eax
  355.         js      @F
  356.  
  357.         cmp     ecx, [ecx+RWSEM.wait_list.next]
  358.         je      .ok
  359. @@:
  360.         sub     esp, sizeof.MUTEX_WAITER
  361.  
  362.         mov     eax, [TASK_BASE]
  363.         mov     [esp+MUTEX_WAITER.task], eax
  364.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
  365.         mov     [eax+TASKDATA.state], 1
  366.  
  367.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  368.  
  369.         call    change_task
  370.  
  371.         add     esp, sizeof.MUTEX_WAITER
  372.         popfd
  373.         ret
  374. .ok:
  375.         inc     eax
  376.         mov     [ecx+RWSEM.count], eax
  377.  
  378.         popfd
  379.         ret
  380.  
  381. ;void __fastcall down_write(struct rw_semaphore *sem)
  382.  
  383. align 4
  384. down_write:
  385.         pushfd
  386.         cli
  387.         sub     esp, sizeof.MUTEX_WAITER
  388.  
  389.         mov     edx, [TASK_BASE]
  390.         mov     [esp+MUTEX_WAITER.task], edx
  391.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
  392.         mov     [edx+TASKDATA.state], 1
  393.  
  394.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  395.  
  396.         xor     eax, eax
  397.         not     eax
  398.  
  399. .forever:
  400.         test    eax, [ecx+RWSEM.count]
  401.         jz      @F
  402.  
  403.         mov     [edx+TASKDATA.state], 1
  404.         call    change_task
  405.         jmp     .forever
  406. @@:
  407.         mov     [ecx+RWSEM.count], eax
  408.         list_del esp
  409.  
  410.         add     esp, sizeof.MUTEX_WAITER
  411.         popfd
  412.         ret
  413.  
  414. ;void __fastcall up_read(struct rw_semaphore *sem)
  415.  
  416. align 4
  417. up_read:
  418.         pushfd
  419.         cli
  420.  
  421.         dec     [ecx+RWSEM.count]
  422.         jnz     @F
  423.  
  424.         mov     eax, [ecx+RWSEM.wait_list.next]
  425.         cmp     eax, ecx
  426.         je      @F
  427.  
  428.         mov     eax, [eax+MUTEX_WAITER.task]
  429.         mov     [eax+TASKDATA.state], 0
  430. @@:
  431.         popfd
  432.         ret
  433.  
  434. ;void __fastcall up_write(struct rw_semaphore *sem)
  435.  
  436. align 4
  437. up_write:
  438.  
  439.         pushfd
  440.         cli
  441.  
  442.         mov     eax, [ecx+RWSEM.wait_list.next]
  443.         mov     [ecx+RWSEM.count], 0
  444.  
  445.         cmp     ecx, eax
  446.         je      .done
  447.  
  448.         mov     edx, [eax+MUTEX_WAITER.type]
  449.         test    edx, edx
  450.         jnz     .wake
  451.  
  452.         mov     eax, [eax+MUTEX_WAITER.task]
  453.         mov     [eax+TASKDATA.state], 0
  454. .done:
  455.         popfd
  456.         ret
  457.  
  458. .wake:
  459.         push    ebx
  460.         push    esi
  461.         push    edi
  462.  
  463.         xor     esi, esi
  464.         mov     edi, ecx
  465.  
  466. .wake_list:
  467.  
  468.         mov     ebx, [eax+MUTEX_WAITER.list.next]
  469.         list_del eax
  470.         mov     edx, [eax+MUTEX_WAITER.task]
  471.         mov     [edx+TASKDATA.state], 0
  472.         inc     esi
  473.         cmp     edi, ebx
  474.         je      .wake_done
  475.  
  476.         mov     ecx, [ebx+MUTEX_WAITER.type]
  477.         test    ecx, ecx
  478.         jz      .wake_done
  479.  
  480.         mov     eax, ebx
  481.         jmp     .wake_list
  482.  
  483. .wake_done:
  484.         add     [edi+RWSEM.count], esi
  485.  
  486.         pop     edi
  487.         pop     esi
  488.         pop     ebx
  489.         popfd
  490.         ret
  491.  
  492.  
  493. purge RWSEM_WAITING_FOR_WRITE
  494. purge RWSEM_WAITING_FOR_READ
  495.  
  496.  
  497. if ~defined sync_inc
  498. sync_inc_fix:
  499. sync_inc fix sync_inc_fix
  500.  
  501. ;simplest mutex.
  502. macro SimpleMutex name
  503. {
  504. ;  iglobal
  505.     name dd 0
  506.     name#.type = 1
  507. ;  endg
  508. }
  509. macro WaitSimpleMutex name
  510. {
  511.   local start_wait,ok
  512. start_wait=$
  513.         cli
  514.         cmp     [name], dword 0
  515.         jz      ok
  516.         sti
  517.         call    change_task
  518.         jmp     start_wait
  519. ok=$
  520.         push    eax
  521.         mov     eax, dword [TASK_BASE+second_base_address]
  522.         mov     eax, [eax+TASKDATA.pid]
  523.         mov     [name], eax
  524.         pop     eax
  525.         sti
  526. }
  527. macro ReleaseSimpleMutex name
  528. {
  529.         mov     [name], dword 0
  530. }
  531. macro TryWaitSimpleMutex name  ;result in eax and in flags
  532. {
  533.   local ok,try_end
  534.         cmp     [name], dword 0
  535.         jz      ok
  536.         xor     eax, eax
  537.         jmp     try_end
  538. ok=$
  539.         xor     eax, eax
  540.         inc     eax
  541. try_end=$
  542. }
  543. macro SimpleCriticalSection name
  544. {
  545. ;  iglobal
  546.     name  dd 0
  547.           dd 0
  548.     name#.type=2
  549. ;  endg
  550. }
  551. macro WaitSimpleCriticalSection name
  552. {
  553.   local start_wait,first_wait,inc_counter,end_wait
  554.         push    eax
  555.         mov     eax, [TASK_BASE+second_base_address]
  556.         mov     eax, [eax+TASKDATA.pid]
  557. start_wait=$
  558.         cli
  559.         cmp     [name], dword 0
  560.         jz      first_wait
  561.         cmp     [name], eax
  562.         jz      inc_counter
  563.         sti
  564.         call    change_task
  565.         jmp     start_wait
  566. first_wait=$
  567.         mov     [name], eax
  568.         mov     [name+4], dword 1
  569.         jmp     end_wait
  570. inc_counter=$
  571.         inc     dword [name+4]
  572. end_wait=$
  573.         sti
  574.         pop     eax
  575. }
  576. macro ReleaseSimpleCriticalSection name
  577. {
  578.   local release_end
  579.         dec     dword [name+4]
  580.         jnz     release_end
  581.         mov     [name], dword 0
  582. release_end=$
  583. }
  584. macro TryWaitSimpleCriticalSection name ;result in eax and in flags
  585. {
  586.   local ok,try_end
  587.         mov     eax, [CURRENT_TASK+second_base_address]
  588.         mov     eax, [eax+TASKDATA.pid]
  589.         cmp     [name], eax
  590.         jz      ok
  591.         cmp     [name], 0
  592.         jz      ok
  593.         xor     eax, eax
  594.         jmp     try_end
  595. ok=$
  596.         xor     eax, eax
  597.         inc     eax
  598. try_end=$
  599. }
  600. _cli equ call MEM_HeapLock
  601. _sti equ call MEM_HeapUnLock
  602. end if
  603.  
  604.