65 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			65 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright © Go Opus Authors (see AUTHORS file)
 | |
| //
 | |
| // License for use of this code is detailed in the LICENSE file
 | |
| 
 | |
| // +build !nolibopusfile
 | |
| 
 | |
| package opus
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| 	"sync/atomic"
 | |
| )
 | |
| 
 | |
| // A map of simple integers to the actual pointers to stream structs. Avoids
 | |
| // passing pointers into the Go heap to C.
 | |
| //
 | |
| // As per the CGo pointers design doc for go 1.6:
 | |
| //
 | |
| // A particular unsafe area is C code that wants to hold on to Go func and
 | |
| // pointer values for future callbacks from C to Go. This works today but is not
 | |
| // permitted by the invariant. It is hard to detect. One safe approach is: Go
 | |
| // code that wants to preserve funcs/pointers stores them into a map indexed by
 | |
| // an int. Go code calls the C code, passing the int, which the C code may store
 | |
| // freely. When the C code wants to call into Go, it passes the int to a Go
 | |
| // function that looks in the map and makes the call. An explicit call is
 | |
| // required to release the value from the map if it is no longer needed, but
 | |
| // that was already true before.
 | |
| //
 | |
| // - https://github.com/golang/proposal/blob/master/design/12416-cgo-pointers.md
 | |
| type streamsMap struct {
 | |
| 	sync.RWMutex
 | |
| 	m       map[uintptr]*Stream
 | |
| 	counter uintptr
 | |
| }
 | |
| 
 | |
| func (sm *streamsMap) Get(id uintptr) *Stream {
 | |
| 	sm.RLock()
 | |
| 	defer sm.RUnlock()
 | |
| 	return sm.m[id]
 | |
| }
 | |
| 
 | |
| func (sm *streamsMap) Del(s *Stream) {
 | |
| 	sm.Lock()
 | |
| 	defer sm.Unlock()
 | |
| 	delete(sm.m, s.id)
 | |
| }
 | |
| 
 | |
| // NextId returns a unique ID for each call.
 | |
| func (sm *streamsMap) NextId() uintptr {
 | |
| 	return atomic.AddUintptr(&sm.counter, 1)
 | |
| }
 | |
| 
 | |
| func (sm *streamsMap) Save(s *Stream) {
 | |
| 	sm.Lock()
 | |
| 	defer sm.Unlock()
 | |
| 	sm.m[s.id] = s
 | |
| }
 | |
| 
 | |
| func newStreamsMap() *streamsMap {
 | |
| 	return &streamsMap{
 | |
| 		counter: 0,
 | |
| 		m:       map[uintptr]*Stream{},
 | |
| 	}
 | |
| }
 |