pax_global_header00006660000000000000000000000064146665002040014515gustar00rootroot0000000000000052 comment=90870c157c45529544b0be0c6529a657e5754c96 chansync-0.6.0/000077500000000000000000000000001466650020400133265ustar00rootroot00000000000000chansync-0.6.0/LICENSE000066400000000000000000000020541466650020400143340ustar00rootroot00000000000000MIT License Copyright (c) 2021 Matt Joiner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. chansync-0.6.0/broadcast-cond.go.go000066400000000000000000000014621466650020400171470ustar00rootroot00000000000000package chansync import ( "github.com/anacrolix/sync" "github.com/anacrolix/chansync/events" ) // Can be used as zero-value. Due to the caller needing to bring their own synchronization, an // equivalent to "sync".Cond.Signal is not provided. BroadcastCond is intended to be selected on // with other channels. type BroadcastCond struct { mu sync.Mutex ch chan struct{} } func (me *BroadcastCond) Broadcast() { me.mu.Lock() defer me.mu.Unlock() if me.ch != nil { close(me.ch) me.ch = nil } } // Should be called before releasing locks on resources that might trigger subsequent Broadcasts. // The channel is closed when the condition changes. func (me *BroadcastCond) Signaled() events.Signaled { me.mu.Lock() defer me.mu.Unlock() if me.ch == nil { me.ch = make(chan struct{}) } return me.ch } chansync-0.6.0/events/000077500000000000000000000000001466650020400146325ustar00rootroot00000000000000chansync-0.6.0/events/events.go000066400000000000000000000004011466650020400164600ustar00rootroot00000000000000package events // Here we'll strongly-type channels to assist correct usage, if possible. type ( Signaled <-chan struct{} Done <-chan struct{} Active <-chan struct{} Signal chan<- struct{} Acquire chan<- struct{} Release <-chan struct{} ) chansync-0.6.0/flag.go000066400000000000000000000033161466650020400145710ustar00rootroot00000000000000package chansync import ( "sync" "sync/atomic" "github.com/anacrolix/chansync/events" ) type ReadOnlyFlag interface { Bool() bool On() events.Active Off() events.Active } // Flag wraps a boolean value that starts as false (off). You can wait for it to be on or off, and // set the value as needed. type Flag struct { mu sync.Mutex // It could be possible to optimize this to only allocate channels when one doesn't exist. on chan struct{} off chan struct{} state atomic.Bool // It could be possible to optimize this away to just checking if the desired on or off channel // is present. inited bool } // To match the SetOnce API. func (me *Flag) IsSet() bool { return me.Bool() } func (me *Flag) Bool() bool { return me.state.Load() } func (me *Flag) On() events.Active { me.mu.Lock() defer me.mu.Unlock() me.init() return me.on } func (me *Flag) Off() events.Active { me.mu.Lock() defer me.mu.Unlock() me.init() return me.off } // Everywhere this is called then checks state and potentially modifies channels so it's probably // not worth using sync.Once. func (me *Flag) init() { if me.inited { return } me.on = make(chan struct{}) me.off = make(chan struct{}) close(me.off) me.inited = true } func (me *Flag) SetBool(b bool) { if b { me.Set() } else { me.Clear() } } func (me *Flag) Set() { if me.state.Load() { return } me.mu.Lock() defer me.mu.Unlock() me.init() if !me.state.CompareAndSwap(false, true) { return } close(me.on) me.off = make(chan struct{}) } func (me *Flag) Clear() { if !me.state.Load() { return } me.mu.Lock() defer me.mu.Unlock() me.init() if !me.state.CompareAndSwap(true, false) { return } close(me.off) me.on = make(chan struct{}) } chansync-0.6.0/go.mod000066400000000000000000000001301466650020400144260ustar00rootroot00000000000000module github.com/anacrolix/chansync go 1.16 require github.com/anacrolix/sync v0.3.0 chansync-0.6.0/go.sum000066400000000000000000000075741466650020400144760ustar00rootroot00000000000000github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/envpprof v1.0.0 h1:AwZ+mBP4rQ5f7JSsrsN3h7M2xDW/xSE66IPVOqlnuUc= github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo= github.com/anacrolix/missinggo v1.2.1 h1:0IE3TqX5y5D0IxeMwTyIgqdDew4QrzcXaaEnJQyjHvw= github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y= github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy6BqESAJVw= github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ= github.com/anacrolix/sync v0.3.0 h1:ZPjTrkqQWEfnYVGTQHh5qNjokWaXnjsyXTJSMsKY0TA= github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c h1:FUUopH4brHNO2kJoNN3pV+OBEYmgraLT/KHZrMM69r0= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= chansync-0.6.0/level.go000066400000000000000000000006211466650020400147630ustar00rootroot00000000000000package chansync import ( "sync" "github.com/anacrolix/chansync/events" ) type LevelTrigger struct { ch chan struct{} initOnce sync.Once } func (me *LevelTrigger) Signal() events.Signal { me.init() return me.ch } func (me *LevelTrigger) Active() events.Active { me.init() return me.ch } func (me *LevelTrigger) init() { me.initOnce.Do(func() { me.ch = make(chan struct{}) }) } chansync-0.6.0/semaphore.go000066400000000000000000000014361466650020400156440ustar00rootroot00000000000000package chansync import ( "github.com/anacrolix/chansync/events" ) // Channel semaphore, as is popular for controlling access to limited resources. Should not be used // zero-initialized. type Semaphore struct { ch chan struct{} } // Returns an initialized semaphore with n slots. func NewSemaphore(n int) Semaphore { return Semaphore{ch: make(chan struct{}, n)} } // Returns a channel for acquiring a slot. func (me Semaphore) Acquire() events.Acquire { return me.ch } // Returns a channel for releasing a slot. func (me Semaphore) Release() events.Release { return me.ch } // Returns the current number of acquired values. func (me Semaphore) Value() int { return len(me.ch) } // Returns the resource count when all are available. func (me Semaphore) Cap() int { return cap(me.ch) } chansync-0.6.0/set-once.go000066400000000000000000000014531466650020400153750ustar00rootroot00000000000000package chansync import ( "sync" "sync/atomic" "github.com/anacrolix/chansync/events" ) // SetOnce is a boolean value that can only be flipped from false to true. type SetOnce struct { ch chan struct{} // Could be faster than trying to receive from ch closed atomic.Bool initOnce sync.Once closeOnce sync.Once } // Returns a channel that is closed when the event is flagged. func (me *SetOnce) Done() events.Done { me.init() return me.ch } func (me *SetOnce) init() { me.initOnce.Do(func() { me.ch = make(chan struct{}) }) } // Set only returns true the first time it is called. func (me *SetOnce) Set() (first bool) { me.closeOnce.Do(func() { me.init() first = true me.closed.Store(true) close(me.ch) }) return } func (me *SetOnce) IsSet() bool { return me.closed.Load() }