Skip to content

Commit

Permalink
v0.4.115 Awaitable CyclicAwaitable
Browse files Browse the repository at this point in the history
  • Loading branch information
haraldrudell committed Oct 26, 2023
1 parent 7e29d8c commit ab31707
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 11 deletions.
11 changes: 11 additions & 0 deletions awaitable-ch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
© 2023-present Harald Rudell <[email protected]> (https://haraldrudell.github.io/haraldrudell/)
All rights reserved
*/

package parl

// AwaitableCh is a channel whose only allowed operation is channel receive
// - AwaitableCh implements a semaphore
// - AwaitableCh transfers no data, instead channel close is the significant event
type AwaitableCh <-chan struct{}
61 changes: 61 additions & 0 deletions awaitable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
© 2023-present Harald Rudell <[email protected]> (https://haraldrudell.github.io/haraldrudell/)
All rights reserved
*/

package parl

import "sync/atomic"

// Awaitable is a semaphore that allows any number of threads to inspect
// and await an event
// - one-to-many, happens-before
// - the synchronization mechanic is closing channel, allowing threads to await
// multiple events
// - status can be inspected in a thread-safe manner: isClosed, isAboutToClose
// allows for race-free consumers
// - Close is idempotent, panic-free
// - if atomic.Pointer[Awaitable] is used for retrieval, a cyclic semaphore is achieved
type Awaitable struct {
isClosed atomic.Bool
ch chan struct{}
}

// NewAwaitable returns a one-to-many sempahore
func NewAwaitable() (awaitable *Awaitable) {
return &Awaitable{ch: make(chan struct{})}
}

// Ch returns an awaitable channel. Thread-safe
func (a *Awaitable) Ch() (ch AwaitableCh) {
return a.ch
}

// isClosed inspects whether the awaitable has been triggered
// - isClosed indicates that the channel is closed
// - isAboutToClose indicates that Close has been invoked,
// but that channel close may still be in progress
// - the two values are requried to attain race-free consumers
// - if isClosed is true, isAboutToClose is also true
// - Thread-safe
func (a *Awaitable) IsClosed() (isClosed, isAboutToClose bool) {
select {
case <-a.ch:
isClosed = true
default:
}
isAboutToClose = a.isClosed.Load()
return
}

// Close triggers awaitable by closing the channel
// - upon return, the channel is guarantee to be closed
// - idempotent, panic-free, thread-safe
func (a *Awaitable) Close() (wasClosed bool) {
if wasClosed = !a.isClosed.CompareAndSwap(false, true); wasClosed {
<-a.ch // wait to make certain the channel is closed
return // already closed return
}
close(a.ch)
return // didClose return
}
88 changes: 88 additions & 0 deletions cyclic-awaitable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
© 2023-present Harald Rudell <[email protected]> (https://haraldrudell.github.io/haraldrudell/)
All rights reserved
*/

package parl

import "sync/atomic"

const (
CyclicAwaitableClosed = true
)

// CyclicAwaitable is an awaitable that can be re-initialized
// - one-to-many, happens-before
// - the synchronization mechanic is closing channel, allowing threads to await
// multiple events
// - status can be inspected in a thread-safe manner: isClosed, isAboutToClose
// allows for race-free consumers
// - Close is idempotent, panic-free
// - if atomic.Pointer[Awaitable] is used for retrieval, a cyclic semaphore is achieved
type CyclicAwaitable struct {
p atomic.Pointer[Awaitable]
}

// NewCyclicAwaitable returns an awaitable that can be re-initialized
// - Init must be invoked prior to use
func NewCyclicAwaitable() (awaitable *CyclicAwaitable) {
return &CyclicAwaitable{}
}

// Init sets the initial state of the awaitable
// - default is not triggered
// - if argument [task.CyclicAwaitableClosed], initial state
// is triggered
func (a *CyclicAwaitable) Init(initiallyClosed ...bool) (a2 *CyclicAwaitable) {
a2 = a
var shouldBeClosed = len(initiallyClosed) > 0 && initiallyClosed[0]
var awaitable = NewAwaitable()
if shouldBeClosed {
awaitable.Close()
}
a.p.Store(awaitable)
return
}

// Ch returns an awaitable channel. Thread-safe
func (a *CyclicAwaitable) Ch() (ch AwaitableCh) {
return a.p.Load().Ch()
}

// isClosed inspects whether the awaitable has been triggered
// - isClosed indicates that the channel is closed
// - isAboutToClose indicates that Close has been invoked,
// but that channel close may still be in progress
// - the two values are requried to attain race-free consumers
// - if isClosed is true, isAboutToClose is also true
// - Thread-safe
func (a *CyclicAwaitable) IsClosed() (isClosed, isAboutToClose bool) {
return a.p.Load().IsClosed()
}

// Close triggers awaitable by closing the channel
// - upon return, the channel is guarantee to be closed
// - idempotent, panic-free, thread-safe
func (a *CyclicAwaitable) Close() (wasClosed bool) {
return a.p.Load().Close()
}

// Open rearms the awaitable for another cycle
// - upon return, the channel is guarantee to be open
// - idempotent, panic-free, thread-safe
func (a *CyclicAwaitable) Open() (didOpen bool) {
var openp *Awaitable
for {
var ap = a.p.Load()
var isClosed, _ = ap.IsClosed()
if !isClosed {
return // was open return
}
if openp == nil {
openp = NewAwaitable()
}
if didOpen = a.p.CompareAndSwap(ap, openp); didOpen {
return // did open the channel return
}
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.21.3

require (
github.com/google/btree v1.1.2
github.com/haraldrudell/parl/yamler v0.4.113
github.com/haraldrudell/parl/yamler v0.4.114
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/sys v0.13.0
golang.org/x/text v0.13.0
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/haraldrudell/parl/yamler v0.4.113 h1:1KLH7UpDPDaYKKjduOYwZHVy3ivKh9iIk6JUnZJ7GC4=
github.com/haraldrudell/parl/yamler v0.4.113/go.mod h1:MpPkrKzB24kQRXV+jskDHMcVYs4UU8hzaaK8IbKoDeE=
github.com/haraldrudell/parl/yamler v0.4.114 h1:Ptpjvn5/38zA+ozoqSdVpirgvDqLWrlGW4ZbkgrYL5M=
github.com/haraldrudell/parl/yamler v0.4.114/go.mod h1:Bd+PCMUuBonpyQX7VMxK5WzWM2gmJ+HxDP53BRxwsv4=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
Expand All @@ -13,6 +13,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
Expand Down
2 changes: 1 addition & 1 deletion mains/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ toolchain go1.21.3
replace github.com/haraldrudell/parl => ../../parl

require (
github.com/haraldrudell/parl v0.4.113
github.com/haraldrudell/parl v0.4.114
golang.org/x/sys v0.13.0
)

Expand Down
2 changes: 1 addition & 1 deletion pterm/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21
replace github.com/haraldrudell/parl => ../../parl

require (
github.com/haraldrudell/parl v0.4.113
github.com/haraldrudell/parl v0.4.114
golang.org/x/term v0.13.0
)

Expand Down
4 changes: 2 additions & 2 deletions sqliter/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ replace github.com/haraldrudell/parl => ../../parl

require (
github.com/google/uuid v1.3.1
github.com/haraldrudell/parl v0.4.113
github.com/haraldrudell/parl v0.4.114
modernc.org/sqlite v1.26.0
)

Expand All @@ -26,7 +26,7 @@ require (
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/ccgo/v3 v3.16.15 // indirect
modernc.org/libc v1.27.0 // indirect
modernc.org/libc v1.28.0 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/opt v0.1.3 // indirect
Expand Down
13 changes: 11 additions & 2 deletions sqliter/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -33,9 +38,11 @@ modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/libc v1.27.0 h1:Z35IJO5v46n+d1RWRzCD3CiMYYc9TotabBDl75kRmdo=
modernc.org/libc v1.27.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.28.0 h1:kHB6LtDBV8DEAK7aZT1vWvP92abW9fb8cjb1P9UTpUE=
modernc.org/libc v1.28.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
Expand All @@ -47,6 +54,8 @@ modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
2 changes: 1 addition & 1 deletion watchfs/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ replace github.com/haraldrudell/parl => ../../parl
require (
github.com/fsnotify/fsnotify v1.7.0
github.com/google/uuid v1.3.1
github.com/haraldrudell/parl v0.4.113
github.com/haraldrudell/parl v0.4.114
)

require (
Expand Down
2 changes: 1 addition & 1 deletion yamler/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ replace github.com/haraldrudell/parl => ../../parl
replace github.com/haraldrudell/parl/mains => ../mains

require (
github.com/haraldrudell/parl v0.4.113
github.com/haraldrudell/parl v0.4.114
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
gopkg.in/yaml.v3 v3.0.1
)
Expand Down

0 comments on commit ab31707

Please sign in to comment.