github.com/mitghi/x@v0.0.0-20191206171256-71e86edf750d/pointers/dcas.go (about) 1 /* MIT License 2 * 3 * Copyright (c) 2018 Mike Taghavi <mitghi[at]gmail.com> 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * The above copyright notice and this permission notice shall be included in all 12 * copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23 package pointers 24 25 import ( 26 "sync/atomic" 27 "unsafe" 28 ) 29 30 /* 31 * implementation of Multi-Word Compare-and-Swap 32 * atomic operation. 33 */ 34 35 // - MARK: Multi-Word Compare-and-Swap Operation section. 36 37 // RDCSSDescriptor is descriptor for Multi-Word CAS. RDCSS 38 // is defined as a restricted form of CAS2 operating atomi- 39 // cally as follow: 40 // 41 // word_t RDCSS(word_t *a1, 42 // word_t o1, 43 // word_t *a2, 44 // word_t o2, 45 // word_t n) { 46 // r = *a2; 47 // if ((r == o2) && (*a1 == o1)) *a2 = n; 48 // return r; 49 // } 50 type RDCSSDescriptor struct { 51 a1 *unsafe.Pointer // control address 52 o1 unsafe.Pointer // expected value 53 a2 *unsafe.Pointer // data address 54 o2 unsafe.Pointer // old value 55 n unsafe.Pointer // new value 56 } 57 58 // RDCSS performs a Double-Compare Single-Swap atomic 59 // operation. It attempts to change data address pointer 60 // `a2` to a `rdcssDescriptor` by comparing it against 61 // old value `o2`. When successfull, the pointer is changed 62 // to new value `n` or re-instiated to `o2` in case of 63 // unsuccessfull operation; A descriptor is active when 64 // referenced from `a2`. Pointer tagging is used to distinct 65 // `rdcssDescriptor` pointers. 66 func RDCSS(a1 *unsafe.Pointer, o1 unsafe.Pointer, a2 *unsafe.Pointer, o2 unsafe.Pointer, n unsafe.Pointer) bool { 67 // Paper: A Practical Multi-Word Compare-and-Swap Operation 68 // by Timothy L. Harris, Keir Fraser and Ian A. Pratt; 69 // University of Cambridge Computer Laboratory, Cambridge, 70 // UK. 71 var ( 72 desc *RDCSSDescriptor = &RDCSSDescriptor{a1, o1, a2, o2, n} 73 dptr unsafe.Pointer 74 ) 75 // add `0x1` tag 76 dptr, _ = TaggedPointer(unsafe.Pointer(desc), 1) 77 if atomic.CompareAndSwapPointer( 78 (*unsafe.Pointer)(unsafe.Pointer(desc.a2)), 79 (unsafe.Pointer)(desc.o2), 80 (unsafe.Pointer)(dptr), 81 ) { 82 return RDCSSComplete(dptr) 83 } 84 return false 85 } 86 87 // RDCSSComplete performs the second stage when descriptor 88 // is succesfully stored in `a2`. It finishes the operation 89 // by swapping `a2` with target pointer `n`. The operation 90 // is successfull, when `a2` is not pointing to RDCSSDescriptor. 91 // In case of unsucessfull operation, `a2` is swapped with `o2` and 92 // returns false. Note, `RDCSSDescriptor` pointers have a 0x1 93 // tag attached to low-order bits. 94 func RDCSSComplete(d unsafe.Pointer) bool { 95 var ( 96 desc *RDCSSDescriptor 97 tgdptr unsafe.Pointer = d 98 dptr unsafe.Pointer = Untag(d) 99 ) 100 desc = (*RDCSSDescriptor)(dptr) 101 if (*desc.a1 == desc.o1) && atomic.CompareAndSwapPointer( 102 (*unsafe.Pointer)(unsafe.Pointer(desc.a2)), 103 (unsafe.Pointer)(unsafe.Pointer(tgdptr)), 104 (unsafe.Pointer)(desc.n), 105 ) { 106 return true 107 } 108 if !atomic.CompareAndSwapPointer( 109 (*unsafe.Pointer)(unsafe.Pointer(desc.a2)), 110 (unsafe.Pointer)(tgdptr), 111 (unsafe.Pointer)(desc.o2), 112 ) { 113 // TODO 114 // . restore ( unable to restore case ) 115 } 116 return false 117 } 118 119 // IsRDCSSDescriptor checks whether the given pointer 120 // `addr` is pointong to `RDCSSDescriptor`or not. According 121 // to original paper ( Section 6.2 ), `RDCSSDescriptor` 122 // pointers can be made distinct by non-zero low-order 123 // bits. A pointer is pointing to `RDCSSDescriptor` iff 124 // `0x1` is present. 125 func IsRDCSSDescriptor(addr unsafe.Pointer) bool { 126 return HasTag(addr) 127 }