1 /******************************************************************************* 2 3 As linux on 64 machines is using only up to 56 bits for the user address 4 space (see https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt) we 5 can use bits from at least 56 to 63 for stuffing in the least significant 8 6 bits of the fd into the epoll registration. This can be used to check if 7 the ISelectClient's registration triggering in epoll wait is made for the 8 previous usage of the ISelectClient (for the wrong fd). This is not 100% 9 accurate, as the file descriptors could be reused but it can be in general 10 this is the best we can to find out expired registrations that are not 11 unregistered from epoll. 12 13 This module provides FdObjEpollData structure that binds fd 14 and the object used at the registration time, so that they both can 15 be registered with epoll and returned with epoll_wait to the user. 16 17 Copyright: 18 Copyright (c) 2017 dunnhumby Germany GmbH. 19 All rights reserved. 20 21 License: 22 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 23 Alternatively, this file may be distributed under the terms of the Tango 24 3-Clause BSD License (see LICENSE_BSD.txt for details). 25 26 *******************************************************************************/ 27 28 module ocean.io.select.selector.EpollFdSanity; 29 30 version (unittest) 31 { 32 import ocean.core.Test; 33 } 34 35 /******************************************************************************* 36 37 Struct binding fd and a Object. 38 39 *******************************************************************************/ 40 41 public struct FdObjEpollData 42 { 43 /// Number of bits to store address in 44 private enum address_bits = 56; 45 46 /// Mask for the user-space address 47 private enum address_mask = (1UL << address_bits) - 1; 48 49 /// Mask for the storing part of the fd 50 private enum fd_mask = ~address_mask; 51 52 static assert(address_mask + fd_mask == ulong.max); 53 54 /// Object instance 55 public Object obj; 56 57 /// client's fd at the time of the registration (least significant byte) 58 private ubyte fd; 59 60 /*************************************************************************** 61 62 Encodes the Object's address and the fd's least significant byte 63 into a ulong, suitable to register with epoll. 64 65 Params: 66 obj = Object to store in the epoll_data instance 67 fd = file descriptor to store the least significant byte of in 68 the epoll_data instance. 69 70 Returns: 71 combination of the Objects's current address and part of the fd 72 to register with the epoll. 73 74 ***************************************************************************/ 75 76 public static ulong encode (Object obj, int fd) 77 { 78 return cast(ulong)( 79 (cast(ulong)cast(void*)obj & address_mask) | 80 (cast(ulong)(fd & 0xFF) << address_bits)); 81 } 82 83 /*************************************************************************** 84 85 Parses the registration to extract the Object and the fd part 86 from it. Reverses the process of encode 87 88 Params: 89 registration = registration containing Object and accompanying 90 fd. 91 92 Returns: 93 FdObjEpollData struct containing Object and accompanying fd. 94 95 ***************************************************************************/ 96 97 public static FdObjEpollData decode (ulong registration) 98 { 99 FdObjEpollData data; 100 data.obj = cast(Object)cast(void*)(registration & address_mask); 101 data.fd = cast(ubyte)((registration & fd_mask) >> address_bits); 102 return data; 103 } 104 105 /*************************************************************************** 106 107 Compares the appropriate byte of the given fd with the instance 108 of this struct. 109 110 Params: 111 fd = fd which we want to confirmed if it was registered with 112 the epoll. 113 114 Returns: 115 true if fd's lowest byte and the byte stored in the registration 116 match, false otherwise 117 118 ***************************************************************************/ 119 120 public bool verifyFd (int fd) 121 { 122 return this.fd == (fd & 0xFF); 123 } 124 } 125 126 /// 127 unittest 128 { 129 auto client = new Object; 130 int fd = 100; 131 auto r = FdObjEpollData.decode(FdObjEpollData.encode(client, fd)); 132 133 test!("is")(client, r.obj); 134 test!("==")(r.verifyFd(fd), true); 135 }