lfstack.goc 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Lock-free stack.
  5. package runtime
  6. #include "runtime.h"
  7. #include "arch.h"
  8. #if __SIZEOF_POINTER__ == 8
  9. // Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
  10. // So we use 17msb of pointers as ABA counter.
  11. # define PTR_BITS 47
  12. #else
  13. # define PTR_BITS 32
  14. #endif
  15. #define PTR_MASK ((1ull<<PTR_BITS)-1)
  16. #define CNT_MASK (0ull-1)
  17. #if __SIZEOF_POINTER__ == 8 && (defined(__sparc__) || (defined(__sun__) && defined(__amd64__)))
  18. // SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
  19. // Use low-order three bits as ABA counter.
  20. // http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
  21. #undef PTR_BITS
  22. #undef CNT_MASK
  23. #undef PTR_MASK
  24. #define PTR_BITS 0
  25. #define CNT_MASK 7
  26. #define PTR_MASK ((0ull-1)<<3)
  27. #endif
  28. void
  29. runtime_lfstackpush(uint64 *head, LFNode *node)
  30. {
  31. uint64 old, new;
  32. if((uintptr)node != ((uintptr)node&PTR_MASK)) {
  33. runtime_printf("p=%p\n", node);
  34. runtime_throw("runtime_lfstackpush: invalid pointer");
  35. }
  36. node->pushcnt++;
  37. new = (uint64)(uintptr)node|(((uint64)node->pushcnt&CNT_MASK)<<PTR_BITS);
  38. for(;;) {
  39. old = runtime_atomicload64(head);
  40. node->next = (LFNode*)(uintptr)(old&PTR_MASK);
  41. if(runtime_cas64(head, old, new))
  42. break;
  43. }
  44. }
  45. LFNode*
  46. runtime_lfstackpop(uint64 *head)
  47. {
  48. LFNode *node, *node2;
  49. uint64 old, new;
  50. for(;;) {
  51. old = runtime_atomicload64(head);
  52. if(old == 0)
  53. return nil;
  54. node = (LFNode*)(uintptr)(old&PTR_MASK);
  55. node2 = runtime_atomicloadp(&node->next);
  56. new = 0;
  57. if(node2 != nil)
  58. new = (uint64)(uintptr)node2|(((uint64)node2->pushcnt&CNT_MASK)<<PTR_BITS);
  59. if(runtime_cas64(head, old, new))
  60. return node;
  61. }
  62. }
  63. func lfstackpush_go(head *uint64, node *LFNode) {
  64. runtime_lfstackpush(head, node);
  65. }
  66. func lfstackpop_go(head *uint64) (node *LFNode) {
  67. node = runtime_lfstackpop(head);
  68. }