]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/mgc0.go
[dev.garbage] all: merge dev.cc (493ad916c3b1) into dev.garbage
[gostls13.git] / src / runtime / mgc0.go
1 // Copyright 2012 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.
4
5 package runtime
6
7 import "unsafe"
8
9 // Called from C. Returns the Go type *m.
10 func gc_m_ptr(ret *interface{}) {
11         *ret = (*m)(nil)
12 }
13
14 // Called from C. Returns the Go type *g.
15 func gc_g_ptr(ret *interface{}) {
16         *ret = (*g)(nil)
17 }
18
19 // Called from C. Returns the Go type *itab.
20 func gc_itab_ptr(ret *interface{}) {
21         *ret = (*itab)(nil)
22 }
23
24 func gc_unixnanotime(now *int64) {
25         sec, nsec := timenow()
26         *now = sec*1e9 + int64(nsec)
27 }
28
29 func freeOSMemory() {
30         gogc(2) // force GC and do eager sweep
31         systemstack(scavenge_m)
32 }
33
34 var poolcleanup func()
35
36 func registerPoolCleanup(f func()) {
37         poolcleanup = f
38 }
39
40 func clearpools() {
41         // clear sync.Pools
42         if poolcleanup != nil {
43                 poolcleanup()
44         }
45
46         for _, p := range &allp {
47                 if p == nil {
48                         break
49                 }
50                 // clear tinyalloc pool
51                 if c := p.mcache; c != nil {
52                         c.tiny = nil
53                         c.tinysize = 0
54
55                         // disconnect cached list before dropping it on the floor,
56                         // so that a dangling ref to one entry does not pin all of them.
57                         var sg, sgnext *sudog
58                         for sg = c.sudogcache; sg != nil; sg = sgnext {
59                                 sgnext = sg.next
60                                 sg.next = nil
61                         }
62                         c.sudogcache = nil
63                 }
64
65                 // clear defer pools
66                 for i := range p.deferpool {
67                         // disconnect cached list before dropping it on the floor,
68                         // so that a dangling ref to one entry does not pin all of them.
69                         var d, dlink *_defer
70                         for d = p.deferpool[i]; d != nil; d = dlink {
71                                 dlink = d.link
72                                 d.link = nil
73                         }
74                         p.deferpool[i] = nil
75                 }
76         }
77 }
78
79 func bgsweep() {
80         sweep.g = getg()
81         getg().issystem = true
82         for {
83                 for gosweepone() != ^uintptr(0) {
84                         sweep.nbgsweep++
85                         Gosched()
86                 }
87                 lock(&gclock)
88                 if !gosweepdone() {
89                         // This can happen if a GC runs between
90                         // gosweepone returning ^0 above
91                         // and the lock being acquired.
92                         unlock(&gclock)
93                         continue
94                 }
95                 sweep.parked = true
96                 goparkunlock(&gclock, "GC sweep wait")
97         }
98 }
99
100 const (
101         _PoisonGC    = 0xf969696969696969 & (1<<(8*ptrSize) - 1)
102         _PoisonStack = 0x6868686868686868 & (1<<(8*ptrSize) - 1)
103 )
104
105 // NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
106 // but if we do that, Go inserts a write barrier on *dst = src.
107 //go:nosplit
108 func writebarrierptr(dst *uintptr, src uintptr) {
109         *dst = src
110         writebarrierptr_nostore(dst, src)
111 }
112
113 // Like writebarrierptr, but the store has already been applied.
114 // Do not reapply.
115 //go:nosplit
116 func writebarrierptr_nostore(dst *uintptr, src uintptr) {
117         if getg() == nil { // very low-level startup
118                 return
119         }
120
121         if src != 0 && (src < _PageSize || src == _PoisonGC || src == _PoisonStack) {
122                 systemstack(func() { gothrow("bad pointer in write barrier") })
123         }
124
125         mp := acquirem()
126         if mp.inwb || mp.dying > 0 {
127                 releasem(mp)
128                 return
129         }
130         mp.inwb = true
131         systemstack(func() {
132                 gcmarkwb_m(dst, src)
133         })
134         mp.inwb = false
135         releasem(mp)
136 }
137
138 //go:nosplit
139 func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
140         writebarrierptr(&dst[0], src[0])
141         dst[1] = src[1]
142 }
143
144 //go:nosplit
145 func writebarrierslice(dst *[3]uintptr, src [3]uintptr) {
146         writebarrierptr(&dst[0], src[0])
147         dst[1] = src[1]
148         dst[2] = src[2]
149 }
150
151 //go:nosplit
152 func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
153         writebarrierptr(&dst[0], src[0])
154         writebarrierptr(&dst[1], src[1])
155 }
156
157 //go:generate go run wbfat_gen.go -- wbfat.go
158 //
159 // The above line generates multiword write barriers for
160 // all the combinations of ptr+scalar up to four words.
161 // The implementations are written to wbfat.go.
162
163 //go:nosplit
164 func writebarrierfat(typ *_type, dst, src unsafe.Pointer) {
165         mask := loadPtrMask(typ)
166         nptr := typ.size / ptrSize
167         for i := uintptr(0); i < nptr; i += 2 {
168                 bits := mask[i/2]
169                 if (bits>>2)&_BitsMask == _BitsPointer {
170                         writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
171                 } else {
172                         *(*uintptr)(dst) = *(*uintptr)(src)
173                 }
174                 dst = add(dst, ptrSize)
175                 src = add(src, ptrSize)
176                 if i+1 == nptr {
177                         break
178                 }
179                 bits >>= 4
180                 if (bits>>2)&_BitsMask == _BitsPointer {
181                         writebarrierptr((*uintptr)(dst), *(*uintptr)(src))
182                 } else {
183                         *(*uintptr)(dst) = *(*uintptr)(src)
184                 }
185                 dst = add(dst, ptrSize)
186                 src = add(src, ptrSize)
187         }
188 }
189
190 //go:nosplit
191 func writebarriercopy(typ *_type, dst, src slice) int {
192         n := dst.len
193         if n > src.len {
194                 n = src.len
195         }
196         if n == 0 {
197                 return 0
198         }
199         dstp := unsafe.Pointer(dst.array)
200         srcp := unsafe.Pointer(src.array)
201
202         if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) {
203                 // Overlap with src before dst.
204                 // Copy backward, being careful not to move dstp/srcp
205                 // out of the array they point into.
206                 dstp = add(dstp, uintptr(n-1)*typ.size)
207                 srcp = add(srcp, uintptr(n-1)*typ.size)
208                 i := uint(0)
209                 for {
210                         writebarrierfat(typ, dstp, srcp)
211                         if i++; i >= n {
212                                 break
213                         }
214                         dstp = add(dstp, -typ.size)
215                         srcp = add(srcp, -typ.size)
216                 }
217         } else {
218                 // Copy forward, being careful not to move dstp/srcp
219                 // out of the array they point into.
220                 i := uint(0)
221                 for {
222                         writebarrierfat(typ, dstp, srcp)
223                         if i++; i >= n {
224                                 break
225                         }
226                         dstp = add(dstp, typ.size)
227                         srcp = add(srcp, typ.size)
228                 }
229         }
230         return int(n)
231 }