blob: f06069d08c4a1510132041bc65f5ae6c69461216 [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 <stdarg.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <lib/fdio/io.h>
#include <lib/zxio/null.h>
#include "private.h"
struct fdio {
const fdio_ops_t* ops;
atomic_int_fast32_t refcount;
int32_t dupcount;
uint32_t ioflag;
zxio_storage_t storage;
};
// 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 = NULL,
.refcount = 1,
.dupcount = 1,
.ioflag = 0,
};
fdio_t* fdio_get_reserved_io(void) {
return &fdio_reserved_io;
}
zxio_t* fdio_get_zxio(fdio_t* io) {
return &io->storage.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) {
fdio_t* io = (fdio_t*) calloc(1, sizeof(fdio_t));
io->ops = ops;
atomic_init(&io->refcount, 1);
return io;
}
void fdio_acquire(fdio_t* io) {
atomic_fetch_add(&io->refcount, 1);
}
void fdio_release(fdio_t* io) {
if (atomic_fetch_sub(&io->refcount, 1) == 1) {
io->ops = NULL;
free(io);
}
}
bool fdio_is_last_reference(fdio_t* io) {
return atomic_load(&io->refcount) == 1;
}