Files

261 lines
6.2 KiB
Go
Raw Permalink Normal View History

// Copyright 2018 The gVisor Authors.
2018-07-09 14:03:03 -07:00
//
// 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.
2018-04-27 10:37:02 -07:00
2018-10-17 15:09:26 -07:00
package transport
2018-04-27 10:37:02 -07:00
import (
"gvisor.dev/gvisor/pkg/atomicbitops"
"gvisor.dev/gvisor/pkg/context"
2019-06-13 16:49:09 -07:00
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/waiter"
2018-04-27 10:37:02 -07:00
)
2018-10-17 15:09:26 -07:00
// queue is a buffer queue.
2018-08-02 10:41:44 -07:00
//
// +stateify savable
2018-10-17 15:09:26 -07:00
type queue struct {
queueRefs
2018-10-20 17:57:19 -07:00
2018-04-27 10:37:02 -07:00
ReaderQueue *waiter.Queue
WriterQueue *waiter.Queue
2022-05-12 18:09:36 -07:00
mu queueMutex `state:"nosave"`
closed atomicbitops.Bool
unread bool
2018-04-27 10:37:02 -07:00
used int64
limit int64
2018-10-17 16:30:11 -07:00
dataList messageList
2018-04-27 10:37:02 -07:00
}
// Close closes q for reading and writing. It is immediately not writable and
// will become unreadable when no more data is pending.
2018-04-27 10:37:02 -07:00
//
// Both the read and write queues must be notified after closing:
2021-03-24 12:08:24 -07:00
// q.ReaderQueue.Notify(waiter.ReadableEvents)
// q.WriterQueue.Notify(waiter.WritableEvents)
2018-10-17 15:09:26 -07:00
func (q *queue) Close() {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
q.closed.Store(true)
2018-04-27 10:37:02 -07:00
q.mu.Unlock()
}
func (q *queue) isClosed() bool {
return q.closed.Load()
}
2018-04-27 10:37:02 -07:00
// Reset empties the queue and Releases all of the Entries.
//
// Both the read and write queues must be notified after resetting:
2021-03-24 12:08:24 -07:00
// q.ReaderQueue.Notify(waiter.ReadableEvents)
// q.WriterQueue.Notify(waiter.WritableEvents)
func (q *queue) Reset(ctx context.Context) {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
dataList := q.dataList
2018-04-27 10:37:02 -07:00
q.dataList.Reset()
q.used = 0
q.mu.Unlock()
for cur := dataList.Front(); cur != nil; cur = cur.Next() {
cur.Release(ctx)
}
2018-04-27 10:37:02 -07:00
}
// DecRef implements RefCounter.DecRef.
func (q *queue) DecRef(ctx context.Context) {
q.queueRefs.DecRef(func() {
// We don't need to notify after resetting because no one cares about
// this queue after all references have been dropped.
q.Reset(ctx)
})
2018-10-20 17:57:19 -07:00
}
2018-04-27 10:37:02 -07:00
// IsReadable determines if q is currently readable.
2018-10-17 15:09:26 -07:00
func (q *queue) IsReadable() bool {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
defer q.mu.Unlock()
return q.closed.RacyLoad() || q.dataList.Front() != nil
2018-04-27 10:37:02 -07:00
}
// bufWritable returns true if there is space for writing.
//
// N.B. Linux only considers a unix socket "writable" if >75% of the buffer is
// free.
//
// See net/unix/af_unix.c:unix_writeable.
2018-10-17 15:09:26 -07:00
func (q *queue) bufWritable() bool {
return 4*q.used < q.limit
}
2018-04-27 10:37:02 -07:00
// IsWritable determines if q is currently writable.
2018-10-17 15:09:26 -07:00
func (q *queue) IsWritable() bool {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
defer q.mu.Unlock()
return q.closed.RacyLoad() || q.bufWritable()
2018-04-27 10:37:02 -07:00
}
// Enqueue adds an entry to the data queue if room is available.
//
// If discardEmpty is true and there are zero bytes of data, the packet is
// dropped.
//
// If truncate is true, Enqueue may truncate the message before enqueuing it.
// Otherwise, the entire message must fit. If l is less than the size of data,
// err indicates why.
//
2018-04-27 10:37:02 -07:00
// If notify is true, ReaderQueue.Notify must be called:
2021-03-24 12:08:24 -07:00
// q.ReaderQueue.Notify(waiter.ReadableEvents)
func (q *queue) Enqueue(ctx context.Context, data [][]byte, c ControlMessages, from Address, discardEmpty bool, truncate bool) (l int64, notify bool, err *syserr.Error) {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
if q.closed.RacyLoad() {
2018-04-27 10:37:02 -07:00
q.mu.Unlock()
2021-11-17 17:04:21 -08:00
return 0, false, syserr.ErrClosedForSend
2018-04-27 10:37:02 -07:00
}
for _, d := range data {
l += int64(len(d))
}
if discardEmpty && l == 0 {
q.mu.Unlock()
c.Release(ctx)
return 0, false, nil
}
free := q.limit - q.used
if l > free && truncate {
if free <= 0 {
// Message can't fit right now.
q.mu.Unlock()
2018-10-24 11:04:11 -07:00
return 0, false, syserr.ErrWouldBlock
}
l = free
2018-10-24 11:04:11 -07:00
err = syserr.ErrWouldBlock
}
if l > q.limit {
// Message is too big to ever fit.
2018-04-27 10:37:02 -07:00
q.mu.Unlock()
2018-10-24 11:04:11 -07:00
return 0, false, syserr.ErrMessageTooLong
}
if l > free {
// Message can't fit right now, and could not be truncated.
q.mu.Unlock()
2018-10-24 11:04:11 -07:00
return 0, false, syserr.ErrWouldBlock
2018-04-27 10:37:02 -07:00
}
// Aggregate l bytes of data. This will truncate the data if l is less than
// the total bytes held in data.
v := make([]byte, l)
for i, b := 0, v; i < len(data) && len(b) > 0; i++ {
n := copy(b, data[i])
b = b[n:]
}
notify = true
q.used += l
q.dataList.PushBack(&message{
2022-06-07 10:33:35 -07:00
Data: v,
Control: c,
Address: from,
})
2018-04-27 10:37:02 -07:00
q.mu.Unlock()
return l, notify, err
2018-04-27 10:37:02 -07:00
}
// Dequeue removes the first entry in the data queue, if one exists.
//
// If notify is true, WriterQueue.Notify must be called:
2021-03-24 12:08:24 -07:00
// q.WriterQueue.Notify(waiter.WritableEvents)
2018-10-24 11:04:11 -07:00
func (q *queue) Dequeue() (e *message, notify bool, err *syserr.Error) {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
if q.dataList.Front() == nil {
2018-10-24 11:04:11 -07:00
err := syserr.ErrWouldBlock
if q.closed.RacyLoad() {
2021-11-17 17:04:21 -08:00
err = syserr.ErrClosedForReceive
if q.unread {
err = syserr.ErrConnectionReset
}
2018-04-27 10:37:02 -07:00
}
q.mu.Unlock()
return nil, false, err
}
2018-10-17 16:30:11 -07:00
e = q.dataList.Front()
2018-04-27 10:37:02 -07:00
q.dataList.Remove(e)
q.used -= e.Length()
notify = q.bufWritable()
2018-04-27 10:37:02 -07:00
q.mu.Unlock()
return e, notify, nil
}
// Peek returns the first entry in the data queue, if one exists.
2018-10-24 11:04:11 -07:00
func (q *queue) Peek() (*message, *syserr.Error) {
2018-04-27 10:37:02 -07:00
q.mu.Lock()
defer q.mu.Unlock()
if q.dataList.Front() == nil {
2018-10-24 11:04:11 -07:00
err := syserr.ErrWouldBlock
if q.closed.RacyLoad() {
2021-11-17 17:04:21 -08:00
if err = syserr.ErrClosedForReceive; q.unread {
err = syserr.ErrConnectionReset
}
2018-04-27 10:37:02 -07:00
}
return nil, err
}
2018-10-17 16:30:11 -07:00
return q.dataList.Front().Peek(), nil
2018-04-27 10:37:02 -07:00
}
// QueuedSize returns the number of bytes currently in the queue, that is, the
// number of readable bytes.
2018-10-17 15:09:26 -07:00
func (q *queue) QueuedSize() int64 {
2018-06-26 12:40:23 -07:00
q.mu.Lock()
defer q.mu.Unlock()
2018-04-27 10:37:02 -07:00
return q.used
}
// MaxQueueSize returns the maximum number of bytes storable in the queue.
2018-10-17 15:09:26 -07:00
func (q *queue) MaxQueueSize() int64 {
q.mu.Lock()
defer q.mu.Unlock()
2018-04-27 10:37:02 -07:00
return q.limit
}
// SetMaxQueueSize sets the maximum number of bytes storable in the queue.
func (q *queue) SetMaxQueueSize(v int64) {
q.mu.Lock()
defer q.mu.Unlock()
q.limit = v
}
// CloseUnread sets flag to indicate that the peer is closed (not shutdown)
// with unread data. So if read on this queue shall return ECONNRESET error.
func (q *queue) CloseUnread() {
q.mu.Lock()
defer q.mu.Unlock()
q.unread = true
}