internal/locker/locker.go (65 lines of code) (raw):

// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Provides the Locker implementations with optional debug utils. package locker import ( "runtime" "sync" "time" "github.com/googlecloudplatform/gcsfuse/v2/internal/logger" ) var gEnableInvariantsCheck bool var gEnableDebugMessages bool // Enable the check for invariants in the locks. Must be set before creating // any lockers. func EnableInvariantsCheck() { gEnableInvariantsCheck = true } // Enable the debug messages to diagnose dead locks. Must be set before creating // any lockers. func EnableDebugMessages() { gEnableDebugMessages = true } type Locker sync.Locker // Returns a locker with potential capability for debugging. func New(name string, check func()) Locker { var l Locker = &sync.Mutex{} if gEnableInvariantsCheck { l = &checker{ locker: l, check: check, } } if gEnableDebugMessages { l = &debugger{ locker: l, name: name, } } return l } type checker struct { locker Locker check func() } func (c *checker) Lock() { c.locker.Lock() c.check() } func (c *checker) Unlock() { c.check() c.locker.Unlock() } type debugger struct { locker Locker name string holder string timer *time.Timer } func (d *debugger) Lock() { d.locker.Lock() buf := make([]byte, 2048) runtime.Stack(buf, false /* all */) d.holder = string(buf) d.timer = time.AfterFunc(5*time.Second, func() { logger.Tracef("debug_mutex: Potential dead lock detected for a lock %q held by: %v\n", d.name, d.holder) }) } func (d *debugger) Unlock() { d.holder = "" d.timer.Stop() d.timer = nil d.locker.Unlock() }