From e6b2d1e0aa80baba32a4f114ebe84230d89e16f5 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Thu, 19 Jan 2023 15:00:46 +0100 Subject: [PATCH] Add helper class to handle close channels. --- closer.go | 47 ++++++++++++++++++++++++++++++++++++++ closer_test.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 closer.go create mode 100644 closer_test.go diff --git a/closer.go b/closer.go new file mode 100644 index 0000000..a68c850 --- /dev/null +++ b/closer.go @@ -0,0 +1,47 @@ +/** + * Standalone signaling server for the Nextcloud Spreed app. + * Copyright (C) 2023 struktur AG + * + * @author Joachim Bauch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package signaling + +import ( + "sync/atomic" +) + +type Closer struct { + closed uint32 + C chan struct{} +} + +func NewCloser() *Closer { + return &Closer{ + C: make(chan struct{}), + } +} + +func (c *Closer) IsClosed() bool { + return atomic.LoadUint32(&c.closed) != 0 +} + +func (c *Closer) Close() { + if atomic.CompareAndSwapUint32(&c.closed, 0, 1) { + close(c.C) + } +} diff --git a/closer_test.go b/closer_test.go new file mode 100644 index 0000000..1a14ea1 --- /dev/null +++ b/closer_test.go @@ -0,0 +1,62 @@ +/** + * Standalone signaling server for the Nextcloud Spreed app. + * Copyright (C) 2023 struktur AG + * + * @author Joachim Bauch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package signaling + +import ( + "sync" + "testing" +) + +func TestCloserMulti(t *testing.T) { + closer := NewCloser() + + var wg sync.WaitGroup + count := 10 + for i := 0; i < count; i++ { + wg.Add(1) + go func() { + defer wg.Done() + <-closer.C + }() + } + + if closer.IsClosed() { + t.Error("should not be closed") + } + closer.Close() + if !closer.IsClosed() { + t.Error("should be closed") + } + wg.Wait() +} + +func TestCloserCloseBeforeWait(t *testing.T) { + closer := NewCloser() + closer.Close() + if !closer.IsClosed() { + t.Error("should be closed") + } + <-closer.C + if !closer.IsClosed() { + t.Error("should be closed") + } +}