1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#pragma once
#include "OS/Handle.h"
#include "OS/FdMap.h"
#include "OS/LinuxIO.h"
#include "Utils/Lock.h"
#if defined(POSIX)
#include <poll.h>
#endif
namespace os {
class ThreadData;
class IORequest;
/**
* IO handle. Encapsulates an OS specific handle to some kind of synchronizing object that the
* OS will notify when IO requests have been completed.
*
* TODO: We could use epoll on Linux for better performance when using many file descriptors.
*/
#if defined(WINDOWS)
class IOHandle {
public:
IOHandle();
IOHandle(HANDLE h);
// Get the underlying handle (if any).
HANDLE v() const;
// Associate a handle to this IO handle.
void add(Handle h, const ThreadData *id);
// Remove association with this IO handle.
void remove(Handle h, const ThreadData *id);
// Process all messages for this IO handle.
void notifyAll(const ThreadData *id) const;
// Close this handle.
void close();
// Attach/detach IO requests.
void attach();
void detach();
private:
HANDLE handle;
// # of requests pending.
mutable size_t pending;
};
#elif defined(POSIX)
/**
* Note: The io_uring implementation is compatible with the interface of the generic POSIX
* interface.
*/
class IOHandle {
public:
IOHandle();
~IOHandle();
// Associate a handle to this IOHandle.
void add(Handle h, const ThreadData *id);
// Remove association of a handle.
void remove(Handle h, const ThreadData *id);
// Attach to this IO handle.
void attach(Handle h, IORequest *request);
// Attach to this IO handle, but call 'remove' on handle afterwards.
void attachAndRemove(Handle h, IORequest *request);
// Detach from this IO handle.
void detach(Handle h, IORequest *request);
// Process all messages for this IO handle.
void notifyAll(const ThreadData *id);
// Close this handle.
void close();
// Get an array of pollfd:s describing the threads waiting currently. Note: The first
// element is empty and available for use by the IOCondition (it puts itself first to wait
// for the IO condition also).
struct Desc {
struct pollfd *fds;
size_t count;
};
Desc desc();
// Additional interface when using io_uring.
#ifdef LINUX_IO_URING
// Cancel a request.
void cancel(IORequest *request);
#endif
private:
// Lock, just in case.
mutable util::Lock lock;
#ifdef LINUX_IO_URING
// Linux IO object.
mutable LinuxIO linuxIO;
// File descriptor to an eventfd that will get notified by the LinuxIO object.
int eventfd;
// pollfd-array to return from 'desc'.
struct pollfd pollfds[2];
// Remember the set of requests that are active currently. We use this to make sure that we
// don't accidentally mess up the stack of threads if we ever get multiple notifications for
// the same fd.
std::unordered_set<IORequest *> activeRequests;
std::multiset<std::pair<int, IORequest *>> activeFDs;
#else
// All handles currently associated with us.
typedef FdMap<IORequest, 1> HandleMap;
HandleMap handles;
#endif
};
#else
#error "Implement IOHandle for your platform!"
#endif
}
|