blob: b6537adbf57e7953c0d95becbb376fd8fef2cd4f [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fdio/fdio.h>
#include <lib/zxio/null.h>
#include <atomic>
#include <cstdarg>
#include <cstdint>
#include "internal.h"
struct fdio {
// The operation function table which encapsulates specialized I/O
// transport under a common interface.
const fdio_ops_t* ops;
// The number of references on this object. Note that each appearance
// in the fd table counts as one reference on the corresponding object.
// Ongoing operations will also contribute to the refcount.
std::atomic_int_fast32_t refcount;
// The number of times this fdio object appears in the fd table.
int32_t dupcount;
// |ioflag| contains mutable properties of this object, shared by
// different transports. Possible values are |IOFLAG_*| in private.h.
uint32_t ioflag;
// The zxio object, if the zxio transport is selected in |ops|.
zxio_storage_t storage;
// Used to implement SO_RCVTIMEO. See `man 7 socket` for details.
zx::duration rcvtimeo;
// Used to implement SO_SNDTIMEO. See `man 7 socket` for details.
zx::duration sndtimeo;
// fdio_reserved_io is a globally shared fdio_t that is used to represent a
// reservation in the fdtab. If a user observes fdio_reserved_io there is a race
// condition in their code or they are looking up fd's by number.
// fdio_reserved_io is used in the time between a user requesting an operation
// that creates and fd, and the time when a remote operation to create the
// backing fdio_t is created, without holding the fdtab lock. Examples include
// open() of a file, or accept() on a socket.
static fdio_t fdio_reserved_io = {
// TODO(raggi): It may be ideal to replace these operations with ones that
// more directly encode the result that a user must have implemented a race
// in order to invoke them.
.ops = nullptr,
.refcount = 1,
.dupcount = 1,
.ioflag = 0,
.storage = {},
.rcvtimeo = zx::duration::infinite(),
.sndtimeo = zx::duration::infinite(),
fdio_t* fdio_get_reserved_io() { return &fdio_reserved_io; }
zxio_t* fdio_get_zxio(fdio_t* io) { return &io->; }
const fdio_ops_t* fdio_get_ops(const fdio_t* io) { return io->ops; }
int32_t fdio_get_dupcount(const fdio_t* io) { return io->dupcount; }
void fdio_dupcount_acquire(fdio_t* io) { io->dupcount++; }
void fdio_dupcount_release(fdio_t* io) { io->dupcount--; }
uint32_t* fdio_get_ioflag(fdio_t* io) { return &io->ioflag; }
zxio_storage_t* fdio_get_zxio_storage(fdio_t* io) { return &io->storage; }
fdio_t* fdio_alloc(const fdio_ops_t* ops) {
return new fdio_t{
.ops = ops,
.refcount = 1,
.dupcount = 0,
.ioflag = 0,
.storage = {},
.rcvtimeo = zx::duration::infinite(),
.sndtimeo = zx::duration::infinite(),
zx::duration* fdio_get_rcvtimeo(fdio_t* io) { return &io->rcvtimeo; }
zx::duration* fdio_get_sndtimeo(fdio_t* io) { return &io->sndtimeo; }
void fdio_acquire(fdio_t* io) { io->refcount.fetch_add(1); }
zx_status_t fdio_release(fdio_t* io) {
if (io->refcount.fetch_sub(1) == 1) {
zx_status_t status = fdio_get_ops(io)->close(io);
delete io;
return status;
return ZX_OK;
bool fdio_is_last_reference(fdio_t* io) { return io->refcount.load() == 1; }