sapling/eden/fs/testharness/FakeFuse.h
Adam Simpkins fef4a43da7 restructure FuseChannel initialization and synchronization
Summary:
- Update FuseChannel::initializate() to not require an Executor.  Rather than
  performing initialization using the supplied Executor, it simply starts one
  worker thread first and performs initialization there.
- Change the API semantics slightly so that the session complete future is
  invoked only if initialization succeeds.  Previously the session complete
  future could be invoked if initialization failed as well.
- Replace the activeThreads counter with a stoppedThreads counter to determine
  when the session complete future should be invoked.  The previous
  activeThreads behavior was somewhat racy, since the activeThreads counter was
  incremented inside each worker thread, but most places that checked it did
  not wait to ensure that all worker threads had successfully incremented it
  yet.

Reviewed By: chadaustin

Differential Revision: D7243910

fbshipit-source-id: 93b3465509bd9bf6fa90ea097e70dac3193172f9
2018-03-13 13:29:03 -07:00

112 lines
3.0 KiB
C++

/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <folly/File.h>
#include <folly/Range.h>
#include <chrono>
#include "eden/third-party/fuse_kernel_linux.h"
namespace facebook {
namespace eden {
/**
* FakeFuse helps implement a fake FUSE device.
*
* FakeFuse is implemented internally as a socket pair. One side behaves like
* the user-space side of a FUSE channel, and the other side behaves like the
* kernel-space side. Test harness code can control the kernel-space side of
* the connection to exercise the EdenMount object that has the user-space side
* of the connection.
*/
class FakeFuse {
public:
struct Response {
fuse_out_header header;
std::vector<uint8_t> body;
};
FakeFuse();
/**
* Start this FakeFuse device, and return the FUSE file descriptor to use to
* communicate with it.
*/
folly::File start();
bool isStarted() const;
/**
* Explicitly close the FUSE descriptor.
*
* The destructor will automatically close the descriptor, but this can be
* used to trigger the close before the FakeFuse object itself is destroyed.
*/
void close();
/**
* Set the timeout for this FakeFuse object.
*
* This will cause recvResponse() to fail with an error if the FUSE
* implementation does not send a response within the specified timeout.
* Similarly, sendRequest() will fail with a timeout if the request cannot be
* written within the given timeout.
*/
void setTimeout(std::chrono::milliseconds timeout);
/**
* Send a new request on the FUSE channel.
*
* Returns the newly allocated request ID.
*/
template <typename ArgType>
uint32_t sendRequest(uint32_t opcode, uint64_t inode, const ArgType& arg) {
folly::ByteRange argBytes(
reinterpret_cast<const uint8_t*>(&arg), sizeof(arg));
return sendRequest(opcode, inode, argBytes);
}
uint32_t sendRequest(uint32_t opcode, uint64_t inode, folly::ByteRange arg);
Response recvResponse();
/**
* Send an INIT request.
*
* Returns the unique request ID.
*/
uint32_t sendInitRequest(
uint32_t majorVersion = FUSE_KERNEL_VERSION,
uint32_t minorVersion = FUSE_KERNEL_MINOR_VERSION,
uint32_t maxReadahead = 0,
uint32_t flags = 0);
private:
FakeFuse(FakeFuse const&) = delete;
FakeFuse& operator=(FakeFuse const&) = delete;
void recvFull(void* buf, size_t len);
/**
* Our end of the FUSE channel.
* We pretend to be the kernel-side of the FUSE connection. We can use this
* connection to send requests to the EdenMount on the other side.
*/
folly::File conn_;
/**
* The next request ID to use when sending requests.
* We increment this for each request we send.
*/
uint32_t requestID_{0};
};
} // namespace eden
} // namespace facebook