1 /* 2 * Copyright 2003-2021 The Music Player Daemon Project 3 * http://www.musicpd.org 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #ifndef EVENT_WINSELECT_BACKEND_HXX 21 #define EVENT_WINSELECT_BACKEND_HXX 22 23 #include "PollResultGeneric.hxx" 24 25 #include <algorithm> 26 #include <cassert> 27 #include <unordered_map> 28 29 #include <winsock2.h> 30 31 class SocketSet 32 { 33 fd_set set; 34 public: SocketSet()35 SocketSet() noexcept { 36 set.fd_count = 0; 37 } 38 SocketSet(const SocketSet & other)39 SocketSet(const SocketSet &other) noexcept { 40 set.fd_count = other.set.fd_count; 41 std::copy_n(other.set.fd_array, set.fd_count, set.fd_array); 42 } 43 GetPtr()44 fd_set *GetPtr() noexcept { 45 return IsEmpty() ? nullptr : &set; 46 } 47 Size() const48 size_t Size() const noexcept { 49 return set.fd_count; 50 } 51 IsEmpty() const52 bool IsEmpty() const noexcept { 53 return set.fd_count == 0; 54 } 55 IsFull() const56 bool IsFull() const noexcept { 57 return set.fd_count == FD_SETSIZE; 58 } 59 operator [](size_t index) const60 SOCKET operator[](size_t index) const noexcept { 61 assert(index < set.fd_count); 62 return set.fd_array[index]; 63 } 64 Add(SOCKET fd)65 size_t Add(SOCKET fd) noexcept { 66 assert(!IsFull()); 67 set.fd_array[set.fd_count] = fd; 68 return set.fd_count++; 69 } 70 MoveToEnd(size_t index)71 void MoveToEnd(size_t index) noexcept { 72 assert(index < set.fd_count); 73 std::swap(set.fd_array[index], set.fd_array[set.fd_count - 1]); 74 } 75 RemoveLast()76 void RemoveLast() noexcept { 77 assert(!IsEmpty()); 78 --set.fd_count; 79 } 80 begin() const81 const auto *begin() const noexcept { 82 return set.fd_array; 83 } 84 end() const85 const auto *end() const noexcept { 86 return set.fd_array + set.fd_count; 87 } 88 }; 89 90 class WinSelectBackend 91 { 92 struct Item 93 { 94 int index[2]{-1, -1}; 95 void *obj; 96 unsigned events = 0; 97 ItemWinSelectBackend::Item98 explicit constexpr Item(void *_obj) noexcept 99 :obj(_obj) {} 100 101 Item(const Item &) = delete; 102 Item &operator=(const Item &) = delete; 103 }; 104 105 SocketSet event_set[2]; 106 std::unordered_map<SOCKET, Item> items; 107 108 public: 109 WinSelectBackend() noexcept; 110 ~WinSelectBackend() noexcept; 111 112 WinSelectBackend(const WinSelectBackend &) = delete; 113 WinSelectBackend &operator=(const WinSelectBackend &) = delete; 114 115 PollResultGeneric ReadEvents(int timeout_ms) noexcept; 116 bool Add(SOCKET fd, unsigned events, void *obj) noexcept; 117 bool Modify(SOCKET fd, unsigned events, void *obj) noexcept; 118 bool Remove(SOCKET fd) noexcept; Abandon(SOCKET fd)119 bool Abandon(SOCKET fd) noexcept { 120 return Remove(fd); 121 } 122 123 private: 124 bool CanModify(Item &item, unsigned events, 125 int event_id) const noexcept; 126 void Modify(Item &item, SOCKET fd, unsigned events, 127 int event_id) noexcept; 128 129 void ApplyReady(const SocketSet &src, unsigned events) noexcept; 130 }; 131 132 #endif 133