kqchan.hpp
1 #ifndef _DARLINGSERVER_KQCHAN_HPP_ 2 #define _DARLINGSERVER_KQCHAN_HPP_ 3 4 #include <memory> 5 #include <optional> 6 #include <deque> 7 8 #include <darlingserver/monitor.hpp> 9 #include <darlingserver/message.hpp> 10 #include <darlingserver/duct-tape.h> 11 #include <darlingserver/logging.hpp> 12 13 #define NOTE_EXIT 0x80000000U 14 #define NOTE_FORK 0x40000000U 15 #define NOTE_EXEC 0x20000000U 16 #define NOTE_REAP 0x10000000U 17 #define NOTE_SIGNAL 0x08000000U 18 #define NOTE_EXITSTATUS 0x04000000U 19 #define NOTE_EXIT_DETAIL 0x02000000U 20 #define NOTE_TRACK 0x00000001U 21 #define NOTE_TRACKERR 0x00000002U 22 #define NOTE_CHILD 0x00000004U 23 #define NOTE_PDATAMASK 0x000fffffU 24 #define NOTE_PCTRLMASK (~(NOTE_PDATAMASK)) 25 26 namespace DarlingServer { 27 class Process; 28 class Thread; 29 30 class Kqchan: public Loggable { 31 friend class DarlingServer::Process; 32 33 protected: 34 uint64_t _debugID; 35 std::weak_ptr<DarlingServer::Process> _process; 36 std::shared_ptr<FD> _socket; 37 std::shared_ptr<Monitor> _monitor; 38 MessageQueue _inbox; 39 MessageQueue _outbox; 40 bool _canSend = false; 41 std::mutex _notificationMutex; 42 bool _canSendNotification = true; 43 bool _deferNotification = false; 44 std::optional<Message> _deferredNotification = std::nullopt; 45 std::mutex _sendingMutex; 46 uint64_t _notificationCount = 0; 47 48 Kqchan(std::shared_ptr<DarlingServer::Process> process); 49 50 virtual uintptr_t _idForProcess() const; 51 52 virtual void _processMessages(); 53 54 virtual std::shared_ptr<Kqchan> sharedFromRoot(); 55 56 void _sendNotification(); 57 void _sendDeferredNotification(); 58 59 public: 60 virtual ~Kqchan(); 61 62 virtual int setup(); 63 64 void logToStream(Log::Stream& stream) const; 65 66 class MachPort; 67 class Process; 68 }; 69 70 71 class Kqchan::MachPort: public Kqchan, public std::enable_shared_from_this<MachPort> { 72 private: 73 uint32_t _port; 74 uint64_t _receiveBuffer; 75 uint64_t _receiveBufferSize; 76 uint64_t _savedFilterFlags; 77 dtape_kqchan_mach_port_t* _dtapeKqchan = nullptr; 78 79 void _modify(uint64_t receiveBuffer, uint64_t receiveBufferSize, uint64_t savedFilterFlags, pid_t nstid); 80 void _read(uint64_t defaultBuffer, uint64_t defaultBufferSize, pid_t nstid); 81 82 void _notify(); 83 84 virtual void _processMessages(); 85 86 /** 87 * This method is used to check for events in an async, lock-safe manner. 88 * This is because the caller may be holding a lock on the kqchan or may even be outside a microthread, 89 * so the actual check needs to be scheduled in a kernel microthread. 90 */ 91 void _checkForEventsAsync(); 92 std::function<void()> _checkForEventsAsyncFactory(); 93 94 protected: 95 virtual uintptr_t _idForProcess() const; 96 97 virtual std::shared_ptr<Kqchan> sharedFromRoot(); 98 99 public: 100 MachPort(std::shared_ptr<DarlingServer::Process> process, uint32_t port, uint64_t receiveBuffer, uint64_t receiveBufferSize, uint64_t savedFilterFlags); 101 ~MachPort(); 102 103 MachPort(const MachPort&) = delete; 104 MachPort& operator=(const MachPort&) = delete; 105 106 MachPort(MachPort&&) = delete; 107 MachPort& operator=(MachPort&&) = delete; 108 109 virtual int setup(); 110 }; 111 112 class Kqchan::Process: public Kqchan, public std::enable_shared_from_this<Process> { 113 friend class DarlingServer::Process; 114 115 private: 116 // some events can be coalesced, but ones like NOTE_FORK and NOTE_EXIT can't be sent in a single event 117 struct Event { 118 public: 119 uint32_t events; 120 int64_t data; 121 std::shared_ptr<Process> newKqchan; 122 }; 123 124 pid_t _nspid; 125 uint32_t _flags; 126 std::mutex _mutex; 127 std::deque<Event> _events; 128 std::weak_ptr<DarlingServer::Process> _targetProcess; 129 bool _attached = false; 130 131 void _modify(uint32_t flags); 132 void _read(); 133 134 void _notify(uint32_t event, int64_t data); 135 136 virtual void _processMessages(); 137 138 /** 139 * See Kqchan::MachPort::_checkForEventsAsync(); this does the same thing for process kqchannels. 140 */ 141 void _checkForEventsAsync(); 142 std::function<void()> _checkForEventsAsyncFactory(); 143 144 protected: 145 virtual uintptr_t _idForProcess() const; 146 147 virtual std::shared_ptr<Kqchan> sharedFromRoot(); 148 149 public: 150 Process(std::shared_ptr<DarlingServer::Process> process, pid_t nspid, uint32_t flags); 151 ~Process(); 152 153 Process(const Process&) = delete; 154 Process& operator=(const Process&) = delete; 155 156 Process(Process&&) = delete; 157 Process& operator=(Process&&) = delete; 158 159 virtual int setup(); 160 161 virtual void logToStream(Log::Stream& stream) const; 162 }; 163 }; 164 165 #endif // _DARLINGSERVER_KQCHAN_HPP_