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  }