Subversion Repositories Kolibri OS

Rev

Rev 6078 | 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: 6240 $
  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
  136.         je      .wait_slow
  137.  
  138.         mov     [esp+SYSCALL_STACK._eax], -2
  139.         ret
  140.  
  141. .wait_slow:
  142.         pushfd
  143.         cli
  144.  
  145.         sub     esp, sizeof.MUTEX_WAITER
  146.         mov     ebx, [TASK_BASE]
  147.         mov     [esp+MUTEX_WAITER.task], ebx
  148.         lea     esi, [ebp+FUTEX.wait_list]
  149.  
  150.         list_add_tail esp, esi      ;esp= new waiter, esi= list head
  151.         mov     eax, edx
  152. .again:
  153.         mov     [ebx+TASKDATA.state], 1
  154.         call    change_task
  155.  
  156.         lock cmpxchg [ecx], edx
  157.         je      .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.         je      .wait_slow_timeout
  178.  
  179.         mov     [esp+SYSCALL_STACK._eax], -2
  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], eax
  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.         mov     eax, edx
  214.         lock cmpxchg [ecx], edx
  215.         jz .again_timeout
  216. @@:
  217.         list_del esp
  218.         add     esp, sizeof.MUTEX_WAITER
  219.  
  220.         popfd
  221.         mov     [esp+SYSCALL_STACK._eax], 0
  222.         ret
  223.  
  224. .timeout:
  225.         list_del esp
  226.         add     esp, sizeof.MUTEX_WAITER
  227.  
  228.         popfd
  229.         mov     [esp+SYSCALL_STACK._eax], -1
  230.         ret
  231.  
  232.  
  233. align 4
  234. ;ecx futex handle
  235. ;edx number of threads
  236. ;edi current process
  237. ;ebp futex object
  238. .futex_wake:
  239.  
  240.         xor     ecx, ecx
  241.  
  242.         pushfd
  243.         cli
  244.  
  245.         lea     ebx, [ebp+FUTEX.wait_list]
  246.         mov     esi, [ebx+LHEAD.next]
  247. .wake:
  248.         cmp     esi, ebx
  249.         je      .done
  250.  
  251.         mov     eax, [esi+MUTEX_WAITER.task]
  252.         mov     [eax+TASKDATA.state], 0
  253.  
  254.         mov     esi, [esi+MUTEX_WAITER.list.next]
  255.         inc     ecx
  256.         cmp     ecx, edx
  257.         jb      .wake
  258. .done:
  259.         popfd
  260.         mov     [esp+SYSCALL_STACK._eax], ecx
  261.         ret
  262.  
  263. RWSEM_WAITING_FOR_WRITE equ 0
  264. RWSEM_WAITING_FOR_READ  equ 1
  265.  
  266. ;void  __fastcall mutex_init(struct mutex *lock)
  267.  
  268. align 4
  269. mutex_init:
  270.         mov     [ecx+MUTEX.wait_list.next], ecx
  271.         mov     [ecx+MUTEX.wait_list.prev], ecx
  272.         mov     [ecx+MUTEX.count], 1
  273.         ret
  274.  
  275. ;void  __fastcall mutex_lock(struct mutex *lock)
  276.  
  277. align 4
  278. mutex_lock:
  279.  
  280.         dec     [ecx+MUTEX.count]
  281.         jns     .done
  282.  
  283.         pushfd
  284.         cli
  285.  
  286.         sub     esp, sizeof.MUTEX_WAITER
  287.  
  288.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  289.  
  290.         mov     edx, [TASK_BASE]
  291.         mov     [esp+MUTEX_WAITER.task], edx
  292.  
  293. .forever:
  294.  
  295.         mov     eax, -1
  296.         xchg    eax, [ecx+MUTEX.count]
  297.         dec     eax
  298.         jz      @F
  299.  
  300.         mov     [edx+TASKDATA.state], 1
  301.         call    change_task
  302.         jmp     .forever
  303. @@:
  304.         mov     eax, ecx
  305.         list_del esp
  306.  
  307.         cmp     [eax+MUTEX.wait_list.next], eax
  308.         jne     @F
  309.  
  310.         mov     [eax+MUTEX.count], 0
  311. @@:
  312.         add     esp, sizeof.MUTEX_WAITER
  313.  
  314.         popfd
  315. .done:
  316.         ret
  317.  
  318. ;void  __fastcall mutex_unlock(struct mutex *lock)
  319.  
  320. align 4
  321. mutex_unlock:
  322.  
  323.         pushfd
  324.         cli
  325.  
  326.         mov     eax, [ecx+MUTEX.wait_list.next]
  327.         cmp     eax, ecx
  328.         mov     [ecx+MUTEX.count], 1
  329.         je      @F
  330.  
  331.         mov     eax, [eax+MUTEX_WAITER.task]
  332.         mov     [eax+TASKDATA.state], 0
  333. @@:
  334.         popfd
  335.         ret
  336.  
  337.  
  338. ;void __fastcall init_rwsem(struct rw_semaphore *sem)
  339.  
  340. align 4
  341. init_rwsem:
  342.         mov     [ecx+RWSEM.wait_list.next], ecx
  343.         mov     [ecx+RWSEM.wait_list.prev], ecx
  344.         mov     [ecx+RWSEM.count], 0
  345.         ret
  346.  
  347. ;void __fastcall down_read(struct rw_semaphore *sem)
  348.  
  349. align 4
  350. down_read:
  351.         pushfd
  352.         cli
  353.  
  354.         mov     eax, [ecx+RWSEM.count]
  355.         test    eax, eax
  356.         js      @F
  357.  
  358.         cmp     ecx, [ecx+RWSEM.wait_list.next]
  359.         je      .ok
  360. @@:
  361.         sub     esp, sizeof.MUTEX_WAITER
  362.  
  363.         mov     eax, [TASK_BASE]
  364.         mov     [esp+MUTEX_WAITER.task], eax
  365.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
  366.         mov     [eax+TASKDATA.state], 1
  367.  
  368.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  369.  
  370.         call    change_task
  371.  
  372.         add     esp, sizeof.MUTEX_WAITER
  373.         popfd
  374.         ret
  375. .ok:
  376.         inc     eax
  377.         mov     [ecx+RWSEM.count], eax
  378.  
  379.         popfd
  380.         ret
  381.  
  382. ;void __fastcall down_write(struct rw_semaphore *sem)
  383.  
  384. align 4
  385. down_write:
  386.         pushfd
  387.         cli
  388.         sub     esp, sizeof.MUTEX_WAITER
  389.  
  390.         mov     edx, [TASK_BASE]
  391.         mov     [esp+MUTEX_WAITER.task], edx
  392.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
  393.         mov     [edx+TASKDATA.state], 1
  394.  
  395.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  396.  
  397.         xor     eax, eax
  398.         not     eax
  399.  
  400. .forever:
  401.         test    eax, [ecx+RWSEM.count]
  402.         jz      @F
  403.  
  404.         mov     [edx+TASKDATA.state], 1
  405.         call    change_task
  406.         jmp     .forever
  407. @@:
  408.         mov     [ecx+RWSEM.count], eax
  409.         list_del esp
  410.  
  411.         add     esp, sizeof.MUTEX_WAITER
  412.         popfd
  413.         ret
  414.  
  415. ;void __fastcall up_read(struct rw_semaphore *sem)
  416.  
  417. align 4
  418. up_read:
  419.         pushfd
  420.         cli
  421.  
  422.         dec     [ecx+RWSEM.count]
  423.         jnz     @F
  424.  
  425.         mov     eax, [ecx+RWSEM.wait_list.next]
  426.         cmp     eax, ecx
  427.         je      @F
  428.  
  429.         mov     eax, [eax+MUTEX_WAITER.task]
  430.         mov     [eax+TASKDATA.state], 0
  431. @@:
  432.         popfd
  433.         ret
  434.  
  435. ;void __fastcall up_write(struct rw_semaphore *sem)
  436.  
  437. align 4
  438. up_write:
  439.  
  440.         pushfd
  441.         cli
  442.  
  443.         mov     eax, [ecx+RWSEM.wait_list.next]
  444.         mov     [ecx+RWSEM.count], 0
  445.  
  446.         cmp     ecx, eax
  447.         je      .done
  448.  
  449.         mov     edx, [eax+MUTEX_WAITER.type]
  450.         test    edx, edx
  451.         jnz     .wake
  452.  
  453.         mov     eax, [eax+MUTEX_WAITER.task]
  454.         mov     [eax+TASKDATA.state], 0
  455. .done:
  456.         popfd
  457.         ret
  458.  
  459. .wake:
  460.         push    ebx
  461.         push    esi
  462.         push    edi
  463.  
  464.         xor     esi, esi
  465.         mov     edi, ecx
  466.  
  467. .wake_list:
  468.  
  469.         mov     ebx, [eax+MUTEX_WAITER.list.next]
  470.         list_del eax
  471.         mov     edx, [eax+MUTEX_WAITER.task]
  472.         mov     [edx+TASKDATA.state], 0
  473.         inc     esi
  474.         cmp     edi, ebx
  475.         je      .wake_done
  476.  
  477.         mov     ecx, [ebx+MUTEX_WAITER.type]
  478.         test    ecx, ecx
  479.         jz      .wake_done
  480.  
  481.         mov     eax, ebx
  482.         jmp     .wake_list
  483.  
  484. .wake_done:
  485.         add     [edi+RWSEM.count], esi
  486.  
  487.         pop     edi
  488.         pop     esi
  489.         pop     ebx
  490.         popfd
  491.         ret
  492.  
  493.  
  494. purge RWSEM_WAITING_FOR_WRITE
  495. purge RWSEM_WAITING_FOR_READ
  496.  
  497.  
  498. if ~defined sync_inc
  499. sync_inc_fix:
  500. sync_inc fix sync_inc_fix
  501.  
  502. ;simplest mutex.
  503. macro SimpleMutex name
  504. {
  505. ;  iglobal
  506.     name dd 0
  507.     name#.type = 1
  508. ;  endg
  509. }
  510. macro WaitSimpleMutex name
  511. {
  512.   local start_wait,ok
  513. start_wait=$
  514.         cli
  515.         cmp     [name], dword 0
  516.         jz      ok
  517.         sti
  518.         call    change_task
  519.         jmp     start_wait
  520. ok=$
  521.         push    eax
  522.         mov     eax, dword [TASK_BASE+second_base_address]
  523.         mov     eax, [eax+TASKDATA.pid]
  524.         mov     [name], eax
  525.         pop     eax
  526.         sti
  527. }
  528. macro ReleaseSimpleMutex name
  529. {
  530.         mov     [name], dword 0
  531. }
  532. macro TryWaitSimpleMutex name  ;result in eax and in flags
  533. {
  534.   local ok,try_end
  535.         cmp     [name], dword 0
  536.         jz      ok
  537.         xor     eax, eax
  538.         jmp     try_end
  539. ok=$
  540.         xor     eax, eax
  541.         inc     eax
  542. try_end=$
  543. }
  544. macro SimpleCriticalSection name
  545. {
  546. ;  iglobal
  547.     name  dd 0
  548.           dd 0
  549.     name#.type=2
  550. ;  endg
  551. }
  552. macro WaitSimpleCriticalSection name
  553. {
  554.   local start_wait,first_wait,inc_counter,end_wait
  555.         push    eax
  556.         mov     eax, [TASK_BASE+second_base_address]
  557.         mov     eax, [eax+TASKDATA.pid]
  558. start_wait=$
  559.         cli
  560.         cmp     [name], dword 0
  561.         jz      first_wait
  562.         cmp     [name], eax
  563.         jz      inc_counter
  564.         sti
  565.         call    change_task
  566.         jmp     start_wait
  567. first_wait=$
  568.         mov     [name], eax
  569.         mov     [name+4], dword 1
  570.         jmp     end_wait
  571. inc_counter=$
  572.         inc     dword [name+4]
  573. end_wait=$
  574.         sti
  575.         pop     eax
  576. }
  577. macro ReleaseSimpleCriticalSection name
  578. {
  579.   local release_end
  580.         dec     dword [name+4]
  581.         jnz     release_end
  582.         mov     [name], dword 0
  583. release_end=$
  584. }
  585. macro TryWaitSimpleCriticalSection name ;result in eax and in flags
  586. {
  587.   local ok,try_end
  588.         mov     eax, [CURRENT_TASK+second_base_address]
  589.         mov     eax, [eax+TASKDATA.pid]
  590.         cmp     [name], eax
  591.         jz      ok
  592.         cmp     [name], 0
  593.         jz      ok
  594.         xor     eax, eax
  595.         jmp     try_end
  596. ok=$
  597.         xor     eax, eax
  598.         inc     eax
  599. try_end=$
  600. }
  601. _cli equ call MEM_HeapLock
  602. _sti equ call MEM_HeapUnLock
  603. end if
  604.  
  605.