2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-07-09 21:03:03 +00: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 17:37:02 +00:00
|
|
|
|
2018-10-17 22:09:26 +00:00
|
|
|
package transport
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
2018-10-21 00:57:19 +00:00
|
|
|
"gvisor.googlesource.com/gvisor/pkg/refs"
|
2018-10-24 18:04:11 +00:00
|
|
|
"gvisor.googlesource.com/gvisor/pkg/syserr"
|
2018-04-27 17:37:02 +00:00
|
|
|
"gvisor.googlesource.com/gvisor/pkg/waiter"
|
|
|
|
)
|
|
|
|
|
2018-10-17 22:09:26 +00:00
|
|
|
// queue is a buffer queue.
|
2018-08-02 17:41:44 +00:00
|
|
|
//
|
|
|
|
// +stateify savable
|
2018-10-17 22:09:26 +00:00
|
|
|
type queue struct {
|
2018-10-21 00:57:19 +00:00
|
|
|
refs.AtomicRefCount
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
ReaderQueue *waiter.Queue
|
|
|
|
WriterQueue *waiter.Queue
|
|
|
|
|
|
|
|
mu sync.Mutex `state:"nosave"`
|
|
|
|
closed bool
|
|
|
|
used int64
|
|
|
|
limit int64
|
2018-10-17 23:30:11 +00:00
|
|
|
dataList messageList
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes q for reading and writing. It is immediately not writable and
|
2018-10-10 21:09:24 +00:00
|
|
|
// will become unreadable when no more data is pending.
|
2018-04-27 17:37:02 +00:00
|
|
|
//
|
|
|
|
// Both the read and write queues must be notified after closing:
|
|
|
|
// q.ReaderQueue.Notify(waiter.EventIn)
|
|
|
|
// q.WriterQueue.Notify(waiter.EventOut)
|
2018-10-17 22:09:26 +00:00
|
|
|
func (q *queue) Close() {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
q.closed = true
|
|
|
|
q.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset empties the queue and Releases all of the Entries.
|
|
|
|
//
|
|
|
|
// Both the read and write queues must be notified after resetting:
|
|
|
|
// q.ReaderQueue.Notify(waiter.EventIn)
|
|
|
|
// q.WriterQueue.Notify(waiter.EventOut)
|
2018-10-17 22:09:26 +00:00
|
|
|
func (q *queue) Reset() {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
for cur := q.dataList.Front(); cur != nil; cur = cur.Next() {
|
2018-10-17 23:30:11 +00:00
|
|
|
cur.Release()
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
q.dataList.Reset()
|
|
|
|
q.used = 0
|
|
|
|
q.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
2018-10-21 00:57:19 +00:00
|
|
|
// DecRef implements RefCounter.DecRef with destructor q.Reset.
|
|
|
|
func (q *queue) DecRef() {
|
|
|
|
q.DecRefWithDestructor(q.Reset)
|
|
|
|
// We don't need to notify after resetting because no one cares about
|
|
|
|
// this queue after all references have been dropped.
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// IsReadable determines if q is currently readable.
|
2018-10-17 22:09:26 +00:00
|
|
|
func (q *queue) IsReadable() bool {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
defer q.mu.Unlock()
|
|
|
|
|
|
|
|
return q.closed || q.dataList.Front() != nil
|
|
|
|
}
|
|
|
|
|
2018-10-10 21:09:24 +00: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 22:09:26 +00:00
|
|
|
func (q *queue) bufWritable() bool {
|
2018-10-10 21:09:24 +00:00
|
|
|
return 4*q.used < q.limit
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// IsWritable determines if q is currently writable.
|
2018-10-17 22:09:26 +00:00
|
|
|
func (q *queue) IsWritable() bool {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
defer q.mu.Unlock()
|
|
|
|
|
2018-10-10 21:09:24 +00:00
|
|
|
return q.closed || q.bufWritable()
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enqueue adds an entry to the data queue if room is available.
|
|
|
|
//
|
2018-10-10 21:09:24 +00:00
|
|
|
// If truncate is true, Enqueue may truncate the message beforing enqueuing it.
|
|
|
|
// Otherwise, the entire message must fit. If n < e.Length(), err indicates why.
|
|
|
|
//
|
2018-04-27 17:37:02 +00:00
|
|
|
// If notify is true, ReaderQueue.Notify must be called:
|
|
|
|
// q.ReaderQueue.Notify(waiter.EventIn)
|
2018-10-24 18:04:11 +00:00
|
|
|
func (q *queue) Enqueue(e *message, truncate bool) (l int64, notify bool, err *syserr.Error) {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
|
|
|
|
if q.closed {
|
|
|
|
q.mu.Unlock()
|
2018-10-24 18:04:11 +00:00
|
|
|
return 0, false, syserr.ErrClosedForSend
|
2018-10-10 21:09:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free := q.limit - q.used
|
|
|
|
|
|
|
|
l = e.Length()
|
|
|
|
|
|
|
|
if l > free && truncate {
|
|
|
|
if free == 0 {
|
|
|
|
// Message can't fit right now.
|
|
|
|
q.mu.Unlock()
|
2018-10-24 18:04:11 +00:00
|
|
|
return 0, false, syserr.ErrWouldBlock
|
2018-10-10 21:09:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
e.Truncate(free)
|
|
|
|
l = e.Length()
|
2018-10-24 18:04:11 +00:00
|
|
|
err = syserr.ErrWouldBlock
|
2018-10-10 21:09:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if l > q.limit {
|
|
|
|
// Message is too big to ever fit.
|
|
|
|
q.mu.Unlock()
|
2018-10-24 18:04:11 +00:00
|
|
|
return 0, false, syserr.ErrMessageTooLong
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
2018-10-10 21:09:24 +00:00
|
|
|
if l > free {
|
|
|
|
// Message can't fit right now.
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Unlock()
|
2018-10-24 18:04:11 +00:00
|
|
|
return 0, false, syserr.ErrWouldBlock
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
notify = q.dataList.Front() == nil
|
2018-10-10 21:09:24 +00:00
|
|
|
q.used += l
|
2018-04-27 17:37:02 +00:00
|
|
|
q.dataList.PushBack(e)
|
|
|
|
|
|
|
|
q.mu.Unlock()
|
|
|
|
|
2018-10-10 21:09:24 +00:00
|
|
|
return l, notify, err
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dequeue removes the first entry in the data queue, if one exists.
|
|
|
|
//
|
|
|
|
// If notify is true, WriterQueue.Notify must be called:
|
|
|
|
// q.WriterQueue.Notify(waiter.EventOut)
|
2018-10-24 18:04:11 +00:00
|
|
|
func (q *queue) Dequeue() (e *message, notify bool, err *syserr.Error) {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
|
|
|
|
if q.dataList.Front() == nil {
|
2018-10-24 18:04:11 +00:00
|
|
|
err := syserr.ErrWouldBlock
|
2018-04-27 17:37:02 +00:00
|
|
|
if q.closed {
|
2018-10-24 18:04:11 +00:00
|
|
|
err = syserr.ErrClosedForReceive
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
q.mu.Unlock()
|
|
|
|
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
|
2018-10-10 21:09:24 +00:00
|
|
|
notify = !q.bufWritable()
|
2018-04-27 17:37:02 +00:00
|
|
|
|
2018-10-17 23:30:11 +00:00
|
|
|
e = q.dataList.Front()
|
2018-04-27 17:37:02 +00:00
|
|
|
q.dataList.Remove(e)
|
|
|
|
q.used -= e.Length()
|
|
|
|
|
2018-10-10 21:09:24 +00:00
|
|
|
notify = notify && q.bufWritable()
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
q.mu.Unlock()
|
|
|
|
|
|
|
|
return e, notify, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Peek returns the first entry in the data queue, if one exists.
|
2018-10-24 18:04:11 +00:00
|
|
|
func (q *queue) Peek() (*message, *syserr.Error) {
|
2018-04-27 17:37:02 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
defer q.mu.Unlock()
|
|
|
|
|
|
|
|
if q.dataList.Front() == nil {
|
2018-10-24 18:04:11 +00:00
|
|
|
err := syserr.ErrWouldBlock
|
2018-04-27 17:37:02 +00:00
|
|
|
if q.closed {
|
2018-10-24 18:04:11 +00:00
|
|
|
err = syserr.ErrClosedForReceive
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-10-17 23:30:11 +00:00
|
|
|
return q.dataList.Front().Peek(), nil
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// QueuedSize returns the number of bytes currently in the queue, that is, the
|
|
|
|
// number of readable bytes.
|
2018-10-17 22:09:26 +00:00
|
|
|
func (q *queue) QueuedSize() int64 {
|
2018-06-26 19:40:23 +00:00
|
|
|
q.mu.Lock()
|
|
|
|
defer q.mu.Unlock()
|
2018-04-27 17:37:02 +00:00
|
|
|
return q.used
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaxQueueSize returns the maximum number of bytes storable in the queue.
|
2018-10-17 22:09:26 +00:00
|
|
|
func (q *queue) MaxQueueSize() int64 {
|
2018-04-27 17:37:02 +00:00
|
|
|
return q.limit
|
|
|
|
}
|