out_message.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2015 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package buffer
  15. import (
  16. "fmt"
  17. "log"
  18. "reflect"
  19. "unsafe"
  20. "github.com/jacobsa/fuse/internal/fusekernel"
  21. )
  22. // OutMessageHeaderSize is the size of the leading header in every
  23. // properly-constructed OutMessage. Reset brings the message back to this size.
  24. const OutMessageHeaderSize = int(unsafe.Sizeof(fusekernel.OutHeader{}))
  25. // OutMessage provides a mechanism for constructing a single contiguous fuse
  26. // message from multiple segments, where the first segment is always a
  27. // fusekernel.OutHeader message.
  28. //
  29. // Must be initialized with Reset.
  30. type OutMessage struct {
  31. // The offset into payload to which we're currently writing.
  32. payloadOffset int
  33. header fusekernel.OutHeader
  34. payload [MaxReadSize]byte
  35. }
  36. // Make sure that the header and payload are contiguous.
  37. func init() {
  38. a := unsafe.Offsetof(OutMessage{}.header) + uintptr(OutMessageHeaderSize)
  39. b := unsafe.Offsetof(OutMessage{}.payload)
  40. if a != b {
  41. log.Panicf(
  42. "header ends at offset %d, but payload starts at offset %d",
  43. a, b)
  44. }
  45. }
  46. // Reset resets m so that it's ready to be used again. Afterward, the contents
  47. // are solely a zeroed fusekernel.OutHeader struct.
  48. func (m *OutMessage) Reset() {
  49. // Ideally we'd like to write:
  50. //
  51. // m.payloadOffset = 0
  52. // m.header = fusekernel.OutHeader{}
  53. //
  54. // But Go 1.8 beta 2 generates bad code for this
  55. // (https://golang.org/issue/18370). Encourage it to generate the same code
  56. // as Go 1.7.4 did.
  57. //if unsafe.Offsetof(m.payload) != 24 {
  58. // panic("unexpected OutMessage layout")
  59. //}
  60. //a := (*[3]uint64)(unsafe.Pointer(m))
  61. //a[0] = 0
  62. //a[1] = 0
  63. //a[2] = 0
  64. m.payloadOffset = 0
  65. m.header = fusekernel.OutHeader{}
  66. }
  67. // OutHeader returns a pointer to the header at the start of the message.
  68. func (m *OutMessage) OutHeader() *fusekernel.OutHeader {
  69. return &m.header
  70. }
  71. // Grow grows m's buffer by the given number of bytes, returning a pointer to
  72. // the start of the new segment, which is guaranteed to be zeroed. If there is
  73. // insufficient space, it returns nil.
  74. func (m *OutMessage) Grow(n int) (p unsafe.Pointer) {
  75. p = m.GrowNoZero(n)
  76. if p != nil {
  77. memclr(p, uintptr(n))
  78. }
  79. return
  80. }
  81. // GrowNoZero is equivalent to Grow, except the new segment is not zeroed. Use
  82. // with caution!
  83. func (m *OutMessage) GrowNoZero(n int) (p unsafe.Pointer) {
  84. // Will we overflow the buffer?
  85. o := m.payloadOffset
  86. if len(m.payload)-o < n {
  87. return
  88. }
  89. p = unsafe.Pointer(uintptr(unsafe.Pointer(&m.payload)) + uintptr(o))
  90. m.payloadOffset = o + n
  91. return
  92. }
  93. // ShrinkTo shrinks m to the given size. It panics if the size is greater than
  94. // Len() or less than OutMessageHeaderSize.
  95. func (m *OutMessage) ShrinkTo(n int) {
  96. if n < OutMessageHeaderSize || n > m.Len() {
  97. panic(fmt.Sprintf(
  98. "ShrinkTo(%d) out of range (current Len: %d)",
  99. n,
  100. m.Len()))
  101. }
  102. m.payloadOffset = n - OutMessageHeaderSize
  103. }
  104. // Append is equivalent to growing by len(src), then copying src over the new
  105. // segment. Int panics if there is not enough room available.
  106. func (m *OutMessage) Append(src []byte) {
  107. p := m.GrowNoZero(len(src))
  108. if p == nil {
  109. panic(fmt.Sprintf("Can't grow %d bytes", len(src)))
  110. }
  111. sh := (*reflect.SliceHeader)(unsafe.Pointer(&src))
  112. memmove(p, unsafe.Pointer(sh.Data), uintptr(sh.Len))
  113. return
  114. }
  115. // AppendString is like Append, but accepts string input.
  116. func (m *OutMessage) AppendString(src string) {
  117. p := m.GrowNoZero(len(src))
  118. if p == nil {
  119. panic(fmt.Sprintf("Can't grow %d bytes", len(src)))
  120. }
  121. sh := (*reflect.StringHeader)(unsafe.Pointer(&src))
  122. memmove(p, unsafe.Pointer(sh.Data), uintptr(sh.Len))
  123. return
  124. }
  125. // Len returns the current size of the message, including the leading header.
  126. func (m *OutMessage) Len() int {
  127. return OutMessageHeaderSize + m.payloadOffset
  128. }
  129. // Bytes returns a reference to the current contents of the buffer, including
  130. // the leading header.
  131. func (m *OutMessage) Bytes() []byte {
  132. l := m.Len()
  133. sh := reflect.SliceHeader{
  134. Data: uintptr(unsafe.Pointer(&m.header)),
  135. Len: l,
  136. Cap: l,
  137. }
  138. return *(*[]byte)(unsafe.Pointer(&sh))
  139. }