3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-11 06:29:29 +01:00

Merge pull request #1607 from slingamn/semaphore_update

simplify semaphore release code
This commit is contained in:
Shivaram Lingamneni 2021-04-07 08:56:53 -04:00 committed by GitHub
commit f0796b2eb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 40 additions and 51 deletions

View File

@ -61,15 +61,15 @@ func NewChannel(s *Server, name, casefoldedName string, registered bool) *Channe
config := s.Config() config := s.Config()
channel := &Channel{ channel := &Channel{
createdTime: time.Now().UTC(), // may be overwritten by applyRegInfo createdTime: time.Now().UTC(), // may be overwritten by applyRegInfo
members: make(MemberSet), members: make(MemberSet),
name: name, name: name,
nameCasefolded: casefoldedName, nameCasefolded: casefoldedName,
server: s, server: s,
writerSemaphore: utils.NewSemaphore(1),
} }
channel.initializeLists() channel.initializeLists()
channel.writerSemaphore.Initialize(1)
channel.history.Initialize(0, 0) channel.history.Initialize(0, 0)
if !registered { if !registered {

View File

@ -356,20 +356,20 @@ func (server *Server) RunClient(conn IRCConn) {
Duration: config.Accounts.LoginThrottling.Duration, Duration: config.Accounts.LoginThrottling.Duration,
Limit: config.Accounts.LoginThrottling.MaxAttempts, Limit: config.Accounts.LoginThrottling.MaxAttempts,
}, },
server: server, server: server,
accountName: "*", accountName: "*",
nick: "*", // * is used until actual nick is given nick: "*", // * is used until actual nick is given
nickCasefolded: "*", nickCasefolded: "*",
nickMaskString: "*", // * is used until actual nick is given nickMaskString: "*", // * is used until actual nick is given
realIP: realIP, realIP: realIP,
proxiedIP: proxiedIP, proxiedIP: proxiedIP,
requireSASL: requireSASL, requireSASL: requireSASL,
nextSessionID: 1, nextSessionID: 1,
writerSemaphore: utils.NewSemaphore(1),
} }
if requireSASL { if requireSASL {
client.requireSASLMessage = banMsg client.requireSASLMessage = banMsg
} }
client.writerSemaphore.Initialize(1)
client.history.Initialize(config.History.ClientLength, time.Duration(config.History.AutoresizeWindow)) client.history.Initialize(config.History.ClientLength, time.Duration(config.History.AutoresizeWindow))
client.brbTimer.Initialize(client) client.brbTimer.Initialize(client)
session := &Session{ session := &Session{
@ -445,6 +445,8 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, channelToStatus m
realname: realname, realname: realname,
nextSessionID: 1, nextSessionID: 1,
writerSemaphore: utils.NewSemaphore(1),
} }
if client.checkAlwaysOnExpirationNoMutex(config, true) { if client.checkAlwaysOnExpirationNoMutex(config, true) {
@ -456,7 +458,6 @@ func (server *Server) AddAlwaysOnClient(account ClientAccount, channelToStatus m
for _, m := range uModes { for _, m := range uModes {
client.SetMode(m, true) client.SetMode(m, true)
} }
client.writerSemaphore.Initialize(1)
client.history.Initialize(0, 0) client.history.Initialize(0, 0)
client.brbTimer.Initialize(client) client.brbTimer.Initialize(client)

View File

@ -37,5 +37,5 @@ func (serversem *ServerSemaphores) Initialize() {
if capacity > MaxServerSemaphoreCapacity { if capacity > MaxServerSemaphoreCapacity {
capacity = MaxServerSemaphoreCapacity capacity = MaxServerSemaphoreCapacity
} }
serversem.ClientDestroy.Initialize(capacity) serversem.ClientDestroy = utils.NewSemaphore(capacity)
} }

View File

@ -612,11 +612,11 @@ func (server *Server) applyConfig(config *Config) (err error) {
if initial { if initial {
maxIPConc := int(config.Server.IPCheckScript.MaxConcurrency) maxIPConc := int(config.Server.IPCheckScript.MaxConcurrency)
if maxIPConc != 0 { if maxIPConc != 0 {
server.semaphores.IPCheckScript.Initialize(maxIPConc) server.semaphores.IPCheckScript = utils.NewSemaphore(maxIPConc)
} }
maxAuthConc := int(config.Accounts.AuthScript.MaxConcurrency) maxAuthConc := int(config.Accounts.AuthScript.MaxConcurrency)
if maxAuthConc != 0 { if maxAuthConc != 0 {
server.semaphores.AuthScript.Initialize(maxAuthConc) server.semaphores.AuthScript = utils.NewSemaphore(maxAuthConc)
} }
if err := overrideServicePrefixes(config.Server.OverrideServicesHostname); err != nil { if err := overrideServicePrefixes(config.Server.OverrideServicesHostname); err != nil {

View File

@ -40,10 +40,10 @@ type Socket struct {
// NewSocket returns a new Socket. // NewSocket returns a new Socket.
func NewSocket(conn IRCConn, maxSendQBytes int) *Socket { func NewSocket(conn IRCConn, maxSendQBytes int) *Socket {
result := Socket{ result := Socket{
conn: conn, conn: conn,
maxSendQBytes: maxSendQBytes, maxSendQBytes: maxSendQBytes,
writerSemaphore: utils.NewSemaphore(1),
} }
result.writerSemaphore.Initialize(1)
return &result return &result
} }

View File

@ -5,8 +5,6 @@ package utils
import ( import (
"context" "context"
"log"
"runtime/debug"
"time" "time"
) )
@ -14,21 +12,21 @@ import (
// A semaphore of capacity 1 can be used as a trylock. // A semaphore of capacity 1 can be used as a trylock.
type Semaphore (chan empty) type Semaphore (chan empty)
// Initialize initializes a semaphore to a given capacity. // NewSemaphore creates and initializes a semaphore to a given capacity.
func (semaphore *Semaphore) Initialize(capacity int) { func NewSemaphore(capacity int) Semaphore {
*semaphore = make(chan empty, capacity) return make(chan empty, capacity)
} }
// Acquire acquires a semaphore, blocking if necessary. // Acquire acquires a semaphore, blocking if necessary.
func (semaphore *Semaphore) Acquire() { func (semaphore Semaphore) Acquire() {
(*semaphore) <- empty{} semaphore <- empty{}
} }
// TryAcquire tries to acquire a semaphore, returning whether the acquire was // TryAcquire tries to acquire a semaphore, returning whether the acquire was
// successful. It never blocks. // successful. It never blocks.
func (semaphore *Semaphore) TryAcquire() (acquired bool) { func (semaphore Semaphore) TryAcquire() (acquired bool) {
select { select {
case (*semaphore) <- empty{}: case semaphore <- empty{}:
return true return true
default: default:
return false return false
@ -38,14 +36,14 @@ func (semaphore *Semaphore) TryAcquire() (acquired bool) {
// AcquireWithTimeout tries to acquire a semaphore, blocking for a maximum // AcquireWithTimeout tries to acquire a semaphore, blocking for a maximum
// of approximately `d` while waiting for it. It returns whether the acquire // of approximately `d` while waiting for it. It returns whether the acquire
// was successful. // was successful.
func (semaphore *Semaphore) AcquireWithTimeout(timeout time.Duration) (acquired bool) { func (semaphore Semaphore) AcquireWithTimeout(timeout time.Duration) (acquired bool) {
if timeout < 0 { if timeout < 0 {
return semaphore.TryAcquire() return semaphore.TryAcquire()
} }
timer := time.NewTimer(timeout) timer := time.NewTimer(timeout)
select { select {
case (*semaphore) <- empty{}: case semaphore <- empty{}:
acquired = true acquired = true
case <-timer.C: case <-timer.C:
acquired = false acquired = false
@ -57,9 +55,9 @@ func (semaphore *Semaphore) AcquireWithTimeout(timeout time.Duration) (acquired
// AcquireWithContext tries to acquire a semaphore, blocking at most until // AcquireWithContext tries to acquire a semaphore, blocking at most until
// the context expires. It returns whether the acquire was successful. // the context expires. It returns whether the acquire was successful.
// Note that if the context is already expired, the acquire may succeed anyway. // Note that if the context is already expired, the acquire may succeed anyway.
func (semaphore *Semaphore) AcquireWithContext(ctx context.Context) (acquired bool) { func (semaphore Semaphore) AcquireWithContext(ctx context.Context) (acquired bool) {
select { select {
case (*semaphore) <- empty{}: case semaphore <- empty{}:
acquired = true acquired = true
case <-ctx.Done(): case <-ctx.Done():
acquired = false acquired = false
@ -67,15 +65,7 @@ func (semaphore *Semaphore) AcquireWithContext(ctx context.Context) (acquired bo
return return
} }
// Release releases a semaphore. It never blocks. (This is not a license // Release releases a semaphore.
// to program spurious releases.) func (semaphore Semaphore) Release() {
func (semaphore *Semaphore) Release() { <-semaphore
select {
case <-(*semaphore):
// good
default:
// spurious release
log.Printf("spurious semaphore release (full to capacity %d)", cap(*semaphore))
debug.PrintStack()
}
} }

View File

@ -10,8 +10,7 @@ import (
func TestTryAcquire(t *testing.T) { func TestTryAcquire(t *testing.T) {
count := 3 count := 3
var sem Semaphore sem := NewSemaphore(count)
sem.Initialize(count)
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
assertEqual(sem.TryAcquire(), true, t) assertEqual(sem.TryAcquire(), true, t)
@ -24,8 +23,7 @@ func TestTryAcquire(t *testing.T) {
} }
func TestAcquireWithTimeout(t *testing.T) { func TestAcquireWithTimeout(t *testing.T) {
var sem Semaphore sem := NewSemaphore(1)
sem.Initialize(1)
assertEqual(sem.TryAcquire(), true, t) assertEqual(sem.TryAcquire(), true, t)