Daily bump.
[official-gcc.git] / libgo / go / net / fd_mutex.go
blob6d5509d7f2a3c7f528adb66a33dc2c2ec20c8e54
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package net
7 import "sync/atomic"
9 // fdMutex is a specialized synchronization primitive
10 // that manages lifetime of an fd and serializes access
11 // to Read and Write methods on netFD.
12 type fdMutex struct {
13 state uint64
14 rsema uint32
15 wsema uint32
18 // fdMutex.state is organized as follows:
19 // 1 bit - whether netFD is closed, if set all subsequent lock operations will fail.
20 // 1 bit - lock for read operations.
21 // 1 bit - lock for write operations.
22 // 20 bits - total number of references (read+write+misc).
23 // 20 bits - number of outstanding read waiters.
24 // 20 bits - number of outstanding write waiters.
25 const (
26 mutexClosed = 1 << 0
27 mutexRLock = 1 << 1
28 mutexWLock = 1 << 2
29 mutexRef = 1 << 3
30 mutexRefMask = (1<<20 - 1) << 3
31 mutexRWait = 1 << 23
32 mutexRMask = (1<<20 - 1) << 23
33 mutexWWait = 1 << 43
34 mutexWMask = (1<<20 - 1) << 43
37 // Read operations must do RWLock(true)/RWUnlock(true).
38 // Write operations must do RWLock(false)/RWUnlock(false).
39 // Misc operations must do Incref/Decref. Misc operations include functions like
40 // setsockopt and setDeadline. They need to use Incref/Decref to ensure that
41 // they operate on the correct fd in presence of a concurrent Close call
42 // (otherwise fd can be closed under their feet).
43 // Close operation must do IncrefAndClose/Decref.
45 // RWLock/Incref return whether fd is open.
46 // RWUnlock/Decref return whether fd is closed and there are no remaining references.
48 func (mu *fdMutex) Incref() bool {
49 for {
50 old := atomic.LoadUint64(&mu.state)
51 if old&mutexClosed != 0 {
52 return false
54 new := old + mutexRef
55 if new&mutexRefMask == 0 {
56 panic("net: inconsistent fdMutex")
58 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
59 return true
64 func (mu *fdMutex) IncrefAndClose() bool {
65 for {
66 old := atomic.LoadUint64(&mu.state)
67 if old&mutexClosed != 0 {
68 return false
70 // Mark as closed and acquire a reference.
71 new := (old | mutexClosed) + mutexRef
72 if new&mutexRefMask == 0 {
73 panic("net: inconsistent fdMutex")
75 // Remove all read and write waiters.
76 new &^= mutexRMask | mutexWMask
77 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
78 // Wake all read and write waiters,
79 // they will observe closed flag after wakeup.
80 for old&mutexRMask != 0 {
81 old -= mutexRWait
82 runtime_Semrelease(&mu.rsema)
84 for old&mutexWMask != 0 {
85 old -= mutexWWait
86 runtime_Semrelease(&mu.wsema)
88 return true
93 func (mu *fdMutex) Decref() bool {
94 for {
95 old := atomic.LoadUint64(&mu.state)
96 if old&mutexRefMask == 0 {
97 panic("net: inconsistent fdMutex")
99 new := old - mutexRef
100 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
101 return new&(mutexClosed|mutexRefMask) == mutexClosed
106 func (mu *fdMutex) RWLock(read bool) bool {
107 var mutexBit, mutexWait, mutexMask uint64
108 var mutexSema *uint32
109 if read {
110 mutexBit = mutexRLock
111 mutexWait = mutexRWait
112 mutexMask = mutexRMask
113 mutexSema = &mu.rsema
114 } else {
115 mutexBit = mutexWLock
116 mutexWait = mutexWWait
117 mutexMask = mutexWMask
118 mutexSema = &mu.wsema
120 for {
121 old := atomic.LoadUint64(&mu.state)
122 if old&mutexClosed != 0 {
123 return false
125 var new uint64
126 if old&mutexBit == 0 {
127 // Lock is free, acquire it.
128 new = (old | mutexBit) + mutexRef
129 if new&mutexRefMask == 0 {
130 panic("net: inconsistent fdMutex")
132 } else {
133 // Wait for lock.
134 new = old + mutexWait
135 if new&mutexMask == 0 {
136 panic("net: inconsistent fdMutex")
139 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
140 if old&mutexBit == 0 {
141 return true
143 runtime_Semacquire(mutexSema)
144 // The signaller has subtracted mutexWait.
149 func (mu *fdMutex) RWUnlock(read bool) bool {
150 var mutexBit, mutexWait, mutexMask uint64
151 var mutexSema *uint32
152 if read {
153 mutexBit = mutexRLock
154 mutexWait = mutexRWait
155 mutexMask = mutexRMask
156 mutexSema = &mu.rsema
157 } else {
158 mutexBit = mutexWLock
159 mutexWait = mutexWWait
160 mutexMask = mutexWMask
161 mutexSema = &mu.wsema
163 for {
164 old := atomic.LoadUint64(&mu.state)
165 if old&mutexBit == 0 || old&mutexRefMask == 0 {
166 panic("net: inconsistent fdMutex")
168 // Drop lock, drop reference and wake read waiter if present.
169 new := (old &^ mutexBit) - mutexRef
170 if old&mutexMask != 0 {
171 new -= mutexWait
173 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
174 if old&mutexMask != 0 {
175 runtime_Semrelease(mutexSema)
177 return new&(mutexClosed|mutexRefMask) == mutexClosed
182 // Implemented in runtime package.
183 func runtime_Semacquire(sema *uint32)
184 func runtime_Semrelease(sema *uint32)