Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1440)

Side by Side Diff: common/sync/mutexpool/pool.go

Issue 2640323003: common/sync/mutexpool: Add mutexpool. (Closed)
Patch Set: Comments. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | common/sync/mutexpool/pool_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 // Package mutexpool implements P, a pool of keyed mutexes. These mutexes are
6 // created on-demand and deleted when no longer referenced, so the pool's
7 // maximum size is a function of the maximum number of concurrent mutexes
8 // held at any given time.
9 //
10 // Package mutexpool is useful when coordinating access to resources that are
11 // not managed by the accessor such as remote resource accesses.
12 package mutexpool
13
14 import (
15 "fmt"
16 "sync"
17 )
18
19 // P is a pool of keyed mutexes. The zero value is a valid empty pool.
20 //
21 // A user can grab an arbitrary Mutex's lock by calling WithMutex with a key.
22 // If something else currently holds that Mutex's lock, WithMutex will block
23 // until it can claim the lock. When a key is no longer in use, it will be
24 // removed from P.
25 type P struct {
26 mutexesLock sync.Mutex
27 mutexes map[interface{}]*mutexEntry
28 }
29
30 func (pc *P) getConfigLock(key interface{}) *mutexEntry {
31 // Does the lock already exist?
32 pc.mutexesLock.Lock()
33 defer pc.mutexesLock.Unlock()
34
35 if me := pc.mutexes[key]; me != nil {
36 me.count++
37 if me.count == 0 {
38 panic(fmt.Errorf("mutex refrerence counter overflow"))
39 }
40 return me
41 }
42
43 if pc.mutexes == nil {
44 pc.mutexes = make(map[interface{}]*mutexEntry)
45 }
46 me := &mutexEntry{
47 count: 1, // Start with one ref.
48 }
49 pc.mutexes[key] = me
50 return me
51 }
52
53 func (pc *P) decRef(me *mutexEntry, key interface{}) {
54 pc.mutexesLock.Lock()
55 defer pc.mutexesLock.Unlock()
56
57 me.count--
58 if me.count == 0 {
59 delete(pc.mutexes, key)
60 }
61 }
62
63 // WithMutex locks the Mutex matching the specified key and executes fn while
64 // holding its lock.
65 //
66 // If a mutex for key doesn't exist, one will be created, and will be
67 // automatically cleaned up when no longer referenced.
68 func (pc *P) WithMutex(key interface{}, fn func()) {
69 // Get a lock for this config key, and increment its reference.
70 me := pc.getConfigLock(key)
71 defer pc.decRef(me, key)
72
73 // Hold this lock's mutex and call "fn".
74 me.Lock()
75 defer me.Unlock()
76
77 fn()
78 }
79
80 type mutexEntry struct {
81 sync.Mutex
82
83 // count is the number of references to this mutexEntry. It is protected
84 // by P's lock.
85 count uint64
86 }
OLDNEW
« no previous file with comments | « no previous file | common/sync/mutexpool/pool_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698