home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / os_SunOS_ultrasparc.s < prev    next >
Encoding:
Text File  |  1998-04-08  |  6.3 KB  |  158 lines

  1. ! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 
  2. !
  3. ! The contents of this file are subject to the Netscape Public License
  4. ! Version 1.0 (the "NPL"); you may not use this file except in
  5. ! compliance with the NPL.  You may obtain a copy of the NPL at
  6. ! http://www.mozilla.org/NPL/
  7. ! Software distributed under the NPL is distributed on an "AS IS" basis,
  8. ! WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  9. ! for the specific language governing rights and limitations under the
  10. ! NPL.
  11. ! The Initial Developer of this code under the NPL is Netscape
  12. ! Communications Corporation.  Portions created by Netscape are
  13. ! Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  14. ! Reserved.
  15. !
  16. !
  17. !  atomic increment, decrement and swap routines for V8+ sparc (ultrasparc)
  18. !  using CAS (compare-and-swap) atomic instructions
  19. !
  20. !  this MUST be compiled with an ultrasparc-aware assembler
  21. !
  22. !  standard asm linkage macros; this module must be compiled
  23. !  with the -P option (use C preprocessor)
  24.  
  25. #include <sys/asm_linkage.h>
  26.  
  27. !  ======================================================================
  28. !
  29. !  Perform the sequence a = a + 1 atomically with respect to other
  30. !  fetch-and-adds to location a in a wait-free fashion.
  31. !
  32. !  usage : val = PR_AtomicIncrement(address)
  33. !  return: current value (you'd think this would be old val)
  34. !
  35. !  -----------------------
  36. !  Note on REGISTER USAGE:
  37. !  as this is a LEAF procedure, a new stack frame is not created;
  38. !  we use the caller's stack frame so what would normally be %i (input)
  39. !  registers are actually %o (output registers).  Also, we must not
  40. !  overwrite the contents of %l (local) registers as they are not
  41. !  assumed to be volatile during calls.
  42. !
  43. !  So, the registers used are:
  44. !     %o0  [input]   - the address of the value to increment
  45. !     %o1  [local]   - work register
  46. !     %o2  [local]   - work register
  47. !     %o3  [local]   - work register
  48. !  -----------------------
  49.  
  50.         ENTRY(PR_AtomicIncrement)       ! standard assembler/ELF prologue
  51.  
  52. retryAI:
  53.         ld      [%o0], %o2              ! set o2 to the current value
  54.         add     %o2, 0x1, %o3           ! calc the new value
  55.         mov     %o3, %o1                ! save the return value
  56.         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
  57.         cmp     %o2, %o3                ! see if we set the value
  58.         bne     retryAI                 ! if not, try again
  59.         nop                             ! empty out the branch pipeline
  60.         retl                            ! return back to the caller
  61.         mov     %o1, %o0                ! set the return code to the new value
  62.  
  63.         SET_SIZE(PR_AtomicIncrement)    ! standard assembler/ELF epilogue
  64.  
  65. !
  66. !  end
  67. !
  68. !  ======================================================================
  69. !
  70.  
  71. !  ======================================================================
  72. !
  73. !  Perform the sequence a = a - 1 atomically with respect to other
  74. !  fetch-and-decs to location a in a wait-free fashion.
  75. !
  76. !  usage : val = PR_AtomicDecrement(address)
  77. !  return: current value (you'd think this would be old val)
  78. !
  79. !  -----------------------
  80. !  Note on REGISTER USAGE:
  81. !  as this is a LEAF procedure, a new stack frame is not created;
  82. !  we use the caller's stack frame so what would normally be %i (input)
  83. !  registers are actually %o (output registers).  Also, we must not
  84. !  overwrite the contents of %l (local) registers as they are not
  85. !  assumed to be volatile during calls.
  86. !
  87. !  So, the registers used are:
  88. !     %o0  [input]   - the address of the value to increment
  89. !     %o1  [local]   - work register
  90. !     %o2  [local]   - work register
  91. !     %o3  [local]   - work register
  92. !  -----------------------
  93.  
  94.         ENTRY(PR_AtomicDecrement)       ! standard assembler/ELF prologue
  95.  
  96. retryAD:
  97.         ld      [%o0], %o2              ! set o2 to the current value
  98.         sub     %o2, 0x1, %o3           ! calc the new value
  99.         mov     %o3, %o1                ! save the return value
  100.         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
  101.         cmp     %o2, %o3                ! see if we set the value
  102.         bne     retryAD                 ! if not, try again
  103.         nop                             ! empty out the branch pipeline
  104.         retl                            ! return back to the caller
  105.         mov     %o1, %o0                ! set the return code to the new value
  106.  
  107.         SET_SIZE(PR_AtomicDecrement)    ! standard assembler/ELF epilogue
  108.  
  109. !
  110. !  end
  111. !
  112. !  ======================================================================
  113. !
  114.  
  115. !  ======================================================================
  116. !
  117. !  Perform the sequence a = b atomically with respect to other
  118. !  fetch-and-stores to location a in a wait-free fashion.
  119. !
  120. !  usage : old_val = PR_AtomicSet(address, newval)
  121. !
  122. !  -----------------------
  123. !  Note on REGISTER USAGE:
  124. !  as this is a LEAF procedure, a new stack frame is not created;
  125. !  we use the caller's stack frame so what would normally be %i (input)
  126. !  registers are actually %o (output registers).  Also, we must not
  127. !  overwrite the contents of %l (local) registers as they are not
  128. !  assumed to be volatile during calls.
  129. !
  130. !  So, the registers used are:
  131. !     %o0  [input]   - the address of the value to increment
  132. !     %o1  [input]   - the new value to set for [%o0]
  133. !     %o2  [local]   - work register
  134. !     %o3  [local]   - work register
  135. !  -----------------------
  136.  
  137.         ENTRY(PR_AtomicSet)             ! standard assembler/ELF prologue
  138.  
  139. retryAS:
  140.         ld      [%o0], %o2              ! set o2 to the current value
  141.         mov     %o1, %o3                ! set up the new value
  142.         cas     [%o0], %o2, %o3         ! atomically set if o0 hasn't changed
  143.         cmp     %o2, %o3                ! see if we set the value
  144.         bne     retryAS                 ! if not, try again
  145.         nop                             ! empty out the branch pipeline
  146.         retl                            ! return back to the caller
  147.         mov     %o3, %o0                ! set the return code to the prev value
  148.  
  149.         SET_SIZE(PR_AtomicSet)          ! standard assembler/ELF epilogue
  150.  
  151. !
  152. !  end
  153. !
  154. !  ======================================================================
  155. !
  156.