Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Go's atomic.Value Implementation

Tech Sep 26 4

Interface Representation in Go

In Go, interface are represented as a combination of type and data pointers:

<code>package main

import (
  "fmt"
  "unsafe"
)

type CustomType struct {
  num int64
}

type InterfaceRep struct {
  typePtr unsafe.Pointer
  dataPtr unsafe.Pointer
}

func inspectInterface(val interface{}) {
  size := unsafe.Sizeof(val)
  fmt.Println("Interface size:", size)

  rep := (*InterfaceRep)(unsafe.Pointer(&val))
  fmt.Println("Type pointer:", rep.typePtr)
  fmt.Println("Data pointer:", rep.dataPtr)
  value := (*int64)(rep.dataPtr)
  fmt.Println("Stored value:", *value)
}

func main() {
  ct := CustomType{num: 42}
  inspectInterface(&ct)
}</code>

This demonstrates two key points:

  1. Interfaces use 128 bits (64 bits for type pointer + 64 bits for data pointer)
  2. We can access interface internals through unsafe pointer operations

atomic.Value Source Analysis

The core implementation uses pointer operations for atomic access:

<code>type Value struct {
  val interface{}
}

type interfaceRep struct {
  typePtr unsafe.Pointer
  dataPtr unsafe.Pointer
}

func (v *Value) Load() interface{} {
  rep := (*interfaceRep)(unsafe.Pointer(v))
  typ := LoadPointer(&rep.typePtr)
  
  if typ == nil || typ == unsafe.Pointer(&initialStoreFlag) {
    return nil
  }
  
  data := LoadPointer(&rep.dataPtr)
  result := new(interfaceRep)
  result.typePtr = typ
  result.dataPtr = data
  return *(*interface{})(unsafe.Pointer(result))
}

var initialStoreFlag byte

func (v *Value) Store(newVal interface{}) {
  if newVal == nil {
    panic("atomic.Value: cannot store nil")
  }
  
  target := (*interfaceRep)(unsafe.Pointer(v))
  source := (*interfaceRep)(unsafe.Pointer(&newVal))
  
  for {
    currentType := LoadPointer(&target.typePtr)
    
    if currentType == nil {
      runtime_procPin()
      if !CompareAndSwapPointer(&target.typePtr, nil, unsafe.Pointer(&initialStoreFlag)) {
        runtime_procUnpin()
        continue
      }
      
      StorePointer(&target.dataPtr, source.dataPtr)
      StorePointer(&target.typePtr, source.typePtr)
      runtime_procUnpin()
      return
    }
    
    if currentType == unsafe.Pointer(&initialStoreFlag) {
      continue
    }
    
    if currentType != source.typePtr {
      panic("atomic.Value: type mismatch during store")
    }
    
    StorePointer(&target.dataPtr, source.dataPtr)
    return
  }
}</code>

Implementation Explanation

The key aspects of the implemantation:

  • interfaceRep mirrors Go's internal interface representation
  • Load performs atomic pointer reads and reconstructs the interface
  • Store uses CAS for initialization and enforces type consistency
  • The initialStoreFlag marks ongoing first-write operations
  • Runtime pinning prevents preemption during critical setcions

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.