Subversion Repositories Kolibri OS

Rev

Rev 5565 | Rev 5596 | 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. ;;                                                              ;;
  11. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  12.  
  13. $Revision: 5593 $
  14.  
  15. align 4
  16. ;struct futex*  __fastcall create_futex(int *ptr)
  17. create_futex:
  18.         push    ecx
  19.         mov     ecx, sizeof.FUTEX
  20.         call    create_object
  21.         pop     ecx
  22.         test    eax, eax
  23.         jz .fail
  24.  
  25.         mov     [eax+FUTEX.magic], 'FUTX'
  26.         mov     [eax+FUTEX.destroy], 0
  27.         mov     [eax+FUTEX.pointer], ecx
  28.         lea     ecx, [eax+FUTEX.wait_list]
  29.         list_init ecx
  30.         mov     [eax+FUTEX.flags], 0
  31. .fail:
  32.         ret
  33.  
  34. iglobal
  35. align 4
  36. f77call:
  37.         dd f77.futex_init     ;0
  38.         dd f77.futex_wait     ;1
  39.         dd f77.futex_wake     ;2
  40. .end:
  41. endg
  42.  
  43. align 4
  44. sys_synchronization:
  45. f77:
  46.         cmp     ebx, (f77call.end-f77call)/4
  47.         jae .fail
  48.  
  49.         jmp     dword [f77call+ebx*4]
  50.  
  51. .fail:
  52.         mov     [esp+SYSCALL_STACK._eax], -1
  53.         ret
  54.  
  55.  
  56. align 4
  57. .futex_init:
  58.         call    create_futex
  59.         test    eax, eax
  60.         jz      @F
  61.         mov     eax, [eax+FUTEX.handle]
  62. @@:
  63.         mov     [esp+SYSCALL_STACK._eax], eax
  64.         ret
  65.  
  66. align 4
  67. ;ecx futex handle
  68. ;edx control value
  69. .futex_wait:
  70.         cmp     ecx, 3
  71.         jb      .epicfail
  72.         cmp     ecx, (PROC.pdt_0 - PROC.htab)/4
  73.         jae     .epicfail
  74.  
  75.         mov     esi, [current_process]
  76.         mov     edi, [esi+PROC.htab+ecx*4]
  77.  
  78.         cmp     [edi+FUTEX.magic], 'FUTX'
  79.         jne     .epicfail
  80.         cmp     [edi+FUTEX.handle], ecx
  81.         jne     .epicfail
  82.  
  83.         mov     ecx, [edi+FUTEX.pointer]
  84.  
  85.         mov     eax, edx
  86.         lock cmpxchg [ecx], edx         ;wait until old_value == new_value
  87.         jz .wait_slow
  88.  
  89.         mov     [esp+SYSCALL_STACK._eax], 0
  90.         ret
  91.  
  92. .wait_slow:
  93.         pushfd
  94.         cli
  95.  
  96.         sub     esp, sizeof.MUTEX_WAITER
  97.         mov     ebx, [TASK_BASE]
  98.         mov     [ebx+TASKDATA.state], 1
  99.         mov     [esp+MUTEX_WAITER.task], ebx
  100.         lea     esi, [edi+FUTEX.wait_list]
  101.  
  102.         list_add_tail esp, esi      ;esp= new waiter, esi= list head
  103.  
  104. .again:
  105.         call    change_task
  106.  
  107.         lock cmpxchg [ecx], edx
  108.         jz .again
  109.  
  110.         list_del esp
  111.         add     esp, sizeof.MUTEX_WAITER
  112.  
  113.         popfd
  114.         mov     [esp+SYSCALL_STACK._eax], 0
  115.         ret
  116.  
  117. .epicfail:
  118.         mov     [esp+SYSCALL_STACK._eax], -1
  119.         ret
  120.  
  121. align 4
  122. ;ecx futex handle
  123. ;edx threads count
  124. .futex_wake:
  125.         cmp     ecx, 3
  126.         jb      .epicfail
  127.         cmp     ecx, (PROC.pdt_0 - PROC.htab)/4
  128.         jae     .epicfail
  129.  
  130.         mov     esi, [current_process]
  131.         mov     edi, [esi+PROC.htab+ecx*4]
  132.  
  133.         cmp     [edi+FUTEX.magic], 'FUTX'
  134.         jne     .epicfail
  135.         cmp     [edi+FUTEX.handle], ecx
  136.         jne     .epicfail
  137.  
  138.         xor     ecx, ecx
  139.  
  140.         pushfd
  141.         cli
  142.  
  143.         lea     ebx, [edi+FUTEX.wait_list]
  144.         mov     esi, [edi+FUTEX.wait_list.next]
  145. @@:
  146.         cmp     esi, ebx
  147.         je      @F
  148.  
  149.         mov     eax, [esi+MUTEX_WAITER.task]
  150.         mov     [eax+TASKDATA.state], 0
  151.  
  152.         mov     esi, [esi+MUTEX_WAITER.list.next]
  153.         inc     ecx
  154.         cmp     ecx, edx
  155.         jb      @B
  156. @@:
  157.         popfd
  158.         mov     [esp+SYSCALL_STACK._eax], ecx
  159.         ret
  160.  
  161. RWSEM_WAITING_FOR_WRITE equ 0
  162. RWSEM_WAITING_FOR_READ  equ 1
  163.  
  164. ;void  __fastcall mutex_init(struct mutex *lock)
  165.  
  166. align 4
  167. mutex_init:
  168.         mov     [ecx+MUTEX.wait_list.next], ecx
  169.         mov     [ecx+MUTEX.wait_list.prev], ecx
  170.         mov     [ecx+MUTEX.count], 1
  171.         ret
  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     eax, ecx
  203.         list_del esp
  204.  
  205.         cmp     [eax+MUTEX.wait_list.next], eax
  206.         jne     @F
  207.  
  208.         mov     [eax+MUTEX.count], 0
  209. @@:
  210.         add     esp, sizeof.MUTEX_WAITER
  211.  
  212.         popfd
  213. .done:
  214.         ret
  215.  
  216. ;void  __fastcall mutex_unlock(struct mutex *lock)
  217.  
  218. align 4
  219. mutex_unlock:
  220.  
  221.         pushfd
  222.         cli
  223.  
  224.         mov     eax, [ecx+MUTEX.wait_list.next]
  225.         cmp     eax, ecx
  226.         mov     [ecx+MUTEX.count], 1
  227.         je      @F
  228.  
  229.         mov     eax, [eax+MUTEX_WAITER.task]
  230.         mov     [eax+TASKDATA.state], 0
  231. @@:
  232.         popfd
  233.         ret
  234.  
  235.  
  236. ;void __fastcall init_rwsem(struct rw_semaphore *sem)
  237.  
  238. align 4
  239. init_rwsem:
  240.         mov     [ecx+RWSEM.wait_list.next], ecx
  241.         mov     [ecx+RWSEM.wait_list.prev], ecx
  242.         mov     [ecx+RWSEM.count], 0
  243.         ret
  244.  
  245. ;void __fastcall down_read(struct rw_semaphore *sem)
  246.  
  247. align 4
  248. down_read:
  249.         pushfd
  250.         cli
  251.  
  252.         mov     eax, [ecx+RWSEM.count]
  253.         test    eax, eax
  254.         js      @F
  255.  
  256.         cmp     ecx, [ecx+RWSEM.wait_list.next]
  257.         je      .ok
  258. @@:
  259.         sub     esp, sizeof.MUTEX_WAITER
  260.  
  261.         mov     eax, [TASK_BASE]
  262.         mov     [esp+MUTEX_WAITER.task], eax
  263.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
  264.         mov     [eax+TASKDATA.state], 1
  265.  
  266.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  267.  
  268.         call    change_task
  269.  
  270.         add     esp, sizeof.MUTEX_WAITER
  271.         popfd
  272.         ret
  273. .ok:
  274.         inc     eax
  275.         mov     [ecx+RWSEM.count], eax
  276.  
  277.         popfd
  278.         ret
  279.  
  280. ;void __fastcall down_write(struct rw_semaphore *sem)
  281.  
  282. align 4
  283. down_write:
  284.         pushfd
  285.         cli
  286.         sub     esp, sizeof.MUTEX_WAITER
  287.  
  288.         mov     edx, [TASK_BASE]
  289.         mov     [esp+MUTEX_WAITER.task], edx
  290.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
  291.         mov     [edx+TASKDATA.state], 1
  292.  
  293.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  294.  
  295.         xor     eax, eax
  296.         not     eax
  297.  
  298. .forever:
  299.         test    eax, [ecx+RWSEM.count]
  300.         jz      @F
  301.  
  302.         mov     [edx+TASKDATA.state], 1
  303.         call    change_task
  304.         jmp     .forever
  305. @@:
  306.         mov     [ecx+RWSEM.count], eax
  307.         list_del esp
  308.  
  309.         add     esp, sizeof.MUTEX_WAITER
  310.         popfd
  311.         ret
  312.  
  313. ;void __fastcall up_read(struct rw_semaphore *sem)
  314.  
  315. align 4
  316. up_read:
  317.         pushfd
  318.         cli
  319.  
  320.         dec     [ecx+RWSEM.count]
  321.         jnz     @F
  322.  
  323.         mov     eax, [ecx+RWSEM.wait_list.next]
  324.         cmp     eax, ecx
  325.         je      @F
  326.  
  327.         mov     eax, [eax+MUTEX_WAITER.task]
  328.         mov     [eax+TASKDATA.state], 0
  329. @@:
  330.         popfd
  331.         ret
  332.  
  333. ;void __fastcall up_write(struct rw_semaphore *sem)
  334.  
  335. align 4
  336. up_write:
  337.  
  338.         pushfd
  339.         cli
  340.  
  341.         mov     eax, [ecx+RWSEM.wait_list.next]
  342.         mov     [ecx+RWSEM.count], 0
  343.  
  344.         cmp     ecx, eax
  345.         je      .done
  346.  
  347.         mov     edx, [eax+MUTEX_WAITER.type]
  348.         test    edx, edx
  349.         jnz     .wake
  350.  
  351.         mov     eax, [eax+MUTEX_WAITER.task]
  352.         mov     [eax+TASKDATA.state], 0
  353. .done:
  354.         popfd
  355.         ret
  356.  
  357. .wake:
  358.         push    ebx
  359.         push    esi
  360.         push    edi
  361.  
  362.         xor     esi, esi
  363.         mov     edi, ecx
  364.  
  365. .wake_list:
  366.  
  367.         mov     ebx, [eax+MUTEX_WAITER.list.next]
  368.         list_del eax
  369.         mov     edx, [eax+MUTEX_WAITER.task]
  370.         mov     [edx+TASKDATA.state], 0
  371.         inc     esi
  372.         cmp     edi, ebx
  373.         je      .wake_done
  374.  
  375.         mov     ecx, [ebx+MUTEX_WAITER.type]
  376.         test    ecx, ecx
  377.         jz      .wake_done
  378.  
  379.         mov     eax, ebx
  380.         jmp     .wake_list
  381.  
  382. .wake_done:
  383.         add     [edi+RWSEM.count], esi
  384.  
  385.         pop     edi
  386.         pop     esi
  387.         pop     ebx
  388.         popfd
  389.         ret
  390.  
  391.  
  392. purge MUTEX_WAITER
  393. purge RWSEM_WAITING_FOR_WRITE
  394. purge RWSEM_WAITING_FOR_READ
  395.  
  396.  
  397. if ~defined sync_inc
  398. sync_inc_fix:
  399. sync_inc fix sync_inc_fix
  400.  
  401. ;simplest mutex.
  402. macro SimpleMutex name
  403. {
  404. ;  iglobal
  405.     name dd 0
  406.     name#.type = 1
  407. ;  endg
  408. }
  409. macro WaitSimpleMutex name
  410. {
  411.   local start_wait,ok
  412. start_wait=$
  413.         cli
  414.         cmp     [name], dword 0
  415.         jz      ok
  416.         sti
  417.         call    change_task
  418.         jmp     start_wait
  419. ok=$
  420.         push    eax
  421.         mov     eax, dword [TASK_BASE+second_base_address]
  422.         mov     eax, [eax+TASKDATA.pid]
  423.         mov     [name], eax
  424.         pop     eax
  425.         sti
  426. }
  427. macro ReleaseSimpleMutex name
  428. {
  429.         mov     [name], dword 0
  430. }
  431. macro TryWaitSimpleMutex name  ;result in eax and in flags
  432. {
  433.   local ok,try_end
  434.         cmp     [name], dword 0
  435.         jz      ok
  436.         xor     eax, eax
  437.         jmp     try_end
  438. ok=$
  439.         xor     eax, eax
  440.         inc     eax
  441. try_end=$
  442. }
  443. macro SimpleCriticalSection name
  444. {
  445. ;  iglobal
  446.     name  dd 0
  447.           dd 0
  448.     name#.type=2
  449. ;  endg
  450. }
  451. macro WaitSimpleCriticalSection name
  452. {
  453.   local start_wait,first_wait,inc_counter,end_wait
  454.         push    eax
  455.         mov     eax, [TASK_BASE+second_base_address]
  456.         mov     eax, [eax+TASKDATA.pid]
  457. start_wait=$
  458.         cli
  459.         cmp     [name], dword 0
  460.         jz      first_wait
  461.         cmp     [name], eax
  462.         jz      inc_counter
  463.         sti
  464.         call    change_task
  465.         jmp     start_wait
  466. first_wait=$
  467.         mov     [name], eax
  468.         mov     [name+4], dword 1
  469.         jmp     end_wait
  470. inc_counter=$
  471.         inc     dword [name+4]
  472. end_wait=$
  473.         sti
  474.         pop     eax
  475. }
  476. macro ReleaseSimpleCriticalSection name
  477. {
  478.   local release_end
  479.         dec     dword [name+4]
  480.         jnz     release_end
  481.         mov     [name], dword 0
  482. release_end=$
  483. }
  484. macro TryWaitSimpleCriticalSection name ;result in eax and in flags
  485. {
  486.   local ok,try_end
  487.         mov     eax, [CURRENT_TASK+second_base_address]
  488.         mov     eax, [eax+TASKDATA.pid]
  489.         cmp     [name], eax
  490.         jz      ok
  491.         cmp     [name], 0
  492.         jz      ok
  493.         xor     eax, eax
  494.         jmp     try_end
  495. ok=$
  496.         xor     eax, eax
  497.         inc     eax
  498. try_end=$
  499. }
  500. _cli equ call MEM_HeapLock
  501. _sti equ call MEM_HeapUnLock
  502. end if
  503.  
  504.