]>
Commit | Line | Data |
---|---|---|
653a5d5d | 1 | #if defined(__sun__) && defined(__svr4__) |
870a0fe4 AT |
2 | #ifdef HAVE_CONFIG_H |
3 | #include "config.h" | |
4 | #endif | |
653a5d5d BH |
5 | #include <port.h> |
6 | #include <sys/port_impl.h> | |
7 | #endif | |
8 | #include <unistd.h> | |
c4c08d4d BH |
9 | #include "mplexer.hh" |
10 | #include "sstuff.hh" | |
11 | #include <iostream> | |
653a5d5d | 12 | |
c4c08d4d | 13 | #include "misc.hh" |
581d2da7 | 14 | |
10f4eea8 | 15 | #include "namespaces.hh" |
c4c08d4d | 16 | |
c4c08d4d BH |
17 | class PortsFDMultiplexer : public FDMultiplexer |
18 | { | |
19 | public: | |
20 | PortsFDMultiplexer(); | |
21 | virtual ~PortsFDMultiplexer() | |
22 | { | |
0d0f9fab | 23 | close(d_portfd); |
c4c08d4d BH |
24 | } |
25 | ||
0e663c3b | 26 | virtual int run(struct timeval* tv, int timeout=500); |
c4c08d4d | 27 | |
27ae2e3c | 28 | virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd=nullptr); |
c4c08d4d BH |
29 | virtual void removeFD(callbackmap_t& cbmap, int fd); |
30 | string getName() | |
31 | { | |
32 | return "solaris completion ports"; | |
33 | } | |
34 | private: | |
35 | int d_portfd; | |
36 | boost::shared_array<port_event_t> d_pevents; | |
37 | static int s_maxevents; // not a hard maximum | |
38 | }; | |
39 | ||
40 | ||
41 | static FDMultiplexer* makePorts() | |
42 | { | |
43 | return new PortsFDMultiplexer(); | |
44 | } | |
45 | ||
46 | static struct PortsRegisterOurselves | |
47 | { | |
48 | PortsRegisterOurselves() { | |
49 | FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makePorts)); // priority 0! | |
50 | } | |
51 | } doItPorts; | |
52 | ||
53 | ||
54 | int PortsFDMultiplexer::s_maxevents=1024; | |
55 | PortsFDMultiplexer::PortsFDMultiplexer() : d_pevents(new port_event_t[s_maxevents]) | |
56 | { | |
57 | d_portfd=port_create(); // not hard max | |
58 | if(d_portfd < 0) | |
59 | throw FDMultiplexerException("Setting up port: "+stringerror()); | |
60 | } | |
61 | ||
27ae2e3c | 62 | void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter, const struct timeval* ttd) |
c4c08d4d | 63 | { |
27ae2e3c | 64 | accountingAddFD(cbmap, fd, toDo, parameter, ttd); |
c4c08d4d | 65 | |
0d0f9fab | 66 | if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) { |
c4c08d4d BH |
67 | cbmap.erase(fd); |
68 | throw FDMultiplexerException("Adding fd to port set: "+stringerror()); | |
69 | } | |
70 | } | |
71 | ||
72 | void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) | |
73 | { | |
74 | if(!cbmap.erase(fd)) | |
335da0ba | 75 | throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer"); |
c4c08d4d | 76 | |
692209f2 | 77 | if(port_dissociate(d_portfd, PORT_SOURCE_FD, fd) < 0 && errno != ENOENT) // it appears under some circumstances, ENOENT will be returned, without this being an error. Apache has this same "fix" |
c4c08d4d BH |
78 | throw FDMultiplexerException("Removing fd from port set: "+stringerror()); |
79 | } | |
80 | ||
0e663c3b | 81 | int PortsFDMultiplexer::run(struct timeval* now, int timeout) |
c4c08d4d BH |
82 | { |
83 | if(d_inrun) { | |
84 | throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); | |
85 | } | |
86 | ||
0e663c3b RG |
87 | struct timespec timeoutspec; |
88 | timeoutspec.tv_sec = time / 1000; | |
89 | timeoutspec.tv_nsec = (time % 1000) * 1000000; | |
0d0f9fab | 90 | unsigned int numevents=1; |
0e663c3b | 91 | int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeoutspec); |
c4c08d4d | 92 | |
273d3305 BH |
93 | /* port_getn has an unusual API - (ret == -1, errno == ETIME) can |
94 | mean partial success; you must check (*numevents) in this case | |
95 | and process anything in there, otherwise you'll never see any | |
96 | events from that object again. We don't care about pure timeouts | |
97 | (ret == -1, errno == ETIME, *numevents == 0) so we don't bother | |
98 | with that case. */ | |
645ee6e4 | 99 | if(ret == -1 && errno!=ETIME) { |
273d3305 | 100 | if(errno!=EINTR) |
625db1cc | 101 | throw FDMultiplexerException("completion port_getn returned error: "+stringerror()); |
273d3305 | 102 | // EINTR is not really an error |
1c0af70d | 103 | gettimeofday(now,0); |
625db1cc BH |
104 | return 0; |
105 | } | |
1c0af70d | 106 | gettimeofday(now,0); |
625db1cc | 107 | if(!numevents) // nothing |
c4c08d4d BH |
108 | return 0; |
109 | ||
110 | d_inrun=true; | |
111 | ||
0d0f9fab BH |
112 | for(unsigned int n=0; n < numevents; ++n) { |
113 | d_iter=d_readCallbacks.find(d_pevents[n].portev_object); | |
c4c08d4d BH |
114 | |
115 | if(d_iter != d_readCallbacks.end()) { | |
ac3da0c2 | 116 | d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter); |
0d0f9fab | 117 | if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, |
232f0877 | 118 | POLLIN, 0) < 0) |
4957a608 | 119 | throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror()); |
abbd6830 | 120 | continue; // so we don't find ourselves as writable again |
c4c08d4d BH |
121 | } |
122 | ||
0d0f9fab | 123 | d_iter=d_writeCallbacks.find(d_pevents[n].portev_object); |
c4c08d4d BH |
124 | |
125 | if(d_iter != d_writeCallbacks.end()) { | |
ac3da0c2 | 126 | d_iter->d_callback(d_iter->d_fd, d_iter->d_parameter); |
0d0f9fab | 127 | if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, |
232f0877 | 128 | POLLOUT, 0) < 0) |
4957a608 | 129 | throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror()); |
c4c08d4d | 130 | } |
c4c08d4d BH |
131 | |
132 | } | |
133 | ||
134 | d_inrun=false; | |
0e663c3b | 135 | return numevents; |
c4c08d4d BH |
136 | } |
137 | ||
138 | #if 0 | |
139 | void acceptData(int fd, boost::any& parameter) | |
140 | { | |
141 | cout<<"Have data on fd "<<fd<<endl; | |
142 | Socket* sock=boost::any_cast<Socket*>(parameter); | |
143 | string packet; | |
144 | IPEndpoint rem; | |
145 | sock->recvFrom(packet, rem); | |
146 | cout<<"Received "<<packet.size()<<" bytes!\n"; | |
147 | } | |
148 | ||
149 | ||
150 | int main() | |
151 | { | |
a5794017 | 152 | Socket s(AF_INET, SOCK_DGRAM); |
c4c08d4d BH |
153 | |
154 | IPEndpoint loc("0.0.0.0", 2000); | |
155 | s.bind(loc); | |
156 | ||
157 | PortsFDMultiplexer sfm; | |
158 | ||
159 | sfm.addReadFD(s.getHandle(), &acceptData, &s); | |
160 | ||
161 | for(int n=0; n < 100 ; ++n) { | |
162 | sfm.run(); | |
163 | } | |
164 | sfm.removeReadFD(s.getHandle()); | |
165 | sfm.removeReadFD(s.getHandle()); | |
166 | } | |
167 | #endif | |
168 | ||
169 |