--- /dev/null
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <unistd.h>
+#include <urcu/ref.h>
+
+#include "fd-handle.h"
+#include <common/error.h>
+
+struct fd_handle {
+ struct urcu_ref ref;
+ int fd;
+};
+
+static void fd_handle_release(struct urcu_ref *ref)
+{
+ int ret;
+ struct fd_handle *handle = container_of(ref, struct fd_handle, ref);
+
+ assert(handle->fd >= 0);
+ ret = close(handle->fd);
+ if (ret == -1) {
+ PERROR("Failed to close file descriptor of fd_handle upon release: fd = %d",
+ handle->fd);
+ }
+
+ free(handle);
+}
+
+LTTNG_HIDDEN
+struct fd_handle *fd_handle_create(int fd)
+{
+ struct fd_handle *handle = NULL;
+
+ if (fd < 0) {
+ ERR("Attempted to create an fd_handle from an invalid file descriptor: fd = %d",
+ fd);
+ goto end;
+ }
+
+ handle = zmalloc(sizeof(*handle));
+ if (!handle) {
+ PERROR("Failed to allocate fd_handle");
+ goto end;
+ }
+
+ urcu_ref_init(&handle->ref);
+ handle->fd = fd;
+
+end:
+ return handle;
+}
+
+LTTNG_HIDDEN
+void fd_handle_get(struct fd_handle *handle)
+{
+ assert(handle);
+ urcu_ref_get(&handle->ref);
+}
+
+LTTNG_HIDDEN
+void fd_handle_put(struct fd_handle *handle)
+{
+ assert(handle);
+ urcu_ref_put(&handle->ref, fd_handle_release);
+}
+
+LTTNG_HIDDEN
+int fd_handle_get_fd(struct fd_handle *handle)
+{
+ assert(handle);
+ return handle->fd;
+}
+
+LTTNG_HIDDEN
+struct fd_handle *fd_handle_copy(const struct fd_handle *handle)
+{
+ struct fd_handle *new_handle = NULL;
+ const int new_fd = dup(handle->fd);
+
+ if (new_fd < 0) {
+ PERROR("Failed to duplicate file descriptor while copying fd_handle: fd = %d", handle->fd);
+ goto end;
+ }
+
+ new_handle = fd_handle_create(new_fd);
+end:
+ return new_handle;
+}
--- /dev/null
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef FD_HANDLE_H
+#define FD_HANDLE_H
+
+#include <common/macros.h>
+
+/*
+ * Wrapper around a file descriptor providing reference counting semantics.
+ *
+ * An fd_handle will close() the underlying file descriptor when its reference
+ * count reaches zero.
+ */
+struct fd_handle;
+
+/* Create a file descriptor handle. */
+LTTNG_HIDDEN
+struct fd_handle *fd_handle_create(int fd);
+
+/* Acquire reference to a file descriptor handle. */
+LTTNG_HIDDEN
+void fd_handle_get(struct fd_handle *handle);
+
+/* Release reference to a file descriptor handle. */
+LTTNG_HIDDEN
+void fd_handle_put(struct fd_handle *handle);
+
+/*
+ * Return the underlying file descriptor of a file descriptor handle.
+ *
+ * This function can't fail.
+ */
+LTTNG_HIDDEN
+int fd_handle_get_fd(struct fd_handle *handle);
+
+/*
+ * Obtain a copy of a file descriptor handle.
+ *
+ * On success, the caller becomes the sole owner of the returned file descriptor
+ * handle. The underlying file descriptor is duplicated using dup(). Refer to
+ * the system documentation for the semantics of dup() for this particular file
+ * descriptor type.
+ */
+LTTNG_HIDDEN
+struct fd_handle *fd_handle_copy(const struct fd_handle *handle);
+
+#endif /* FS_HANDLE_H */