diff options
Diffstat (limited to 'linden/indra/llmessage/llpumpio.cpp')
-rw-r--r-- | linden/indra/llmessage/llpumpio.cpp | 222 |
1 files changed, 174 insertions, 48 deletions
diff --git a/linden/indra/llmessage/llpumpio.cpp b/linden/indra/llmessage/llpumpio.cpp index 57bf45b..f60ee2b 100644 --- a/linden/indra/llmessage/llpumpio.cpp +++ b/linden/indra/llmessage/llpumpio.cpp | |||
@@ -14,12 +14,12 @@ | |||
14 | * ("GPL"), unless you have obtained a separate licensing agreement | 14 | * ("GPL"), unless you have obtained a separate licensing agreement |
15 | * ("Other License"), formally executed by you and Linden Lab. Terms of | 15 | * ("Other License"), formally executed by you and Linden Lab. Terms of |
16 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | 16 | * the GPL can be found in doc/GPL-license.txt in this distribution, or |
17 | * online at http://secondlife.com/developers/opensource/gplv2 | 17 | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 |
18 | * | 18 | * |
19 | * There are special exceptions to the terms and conditions of the GPL as | 19 | * There are special exceptions to the terms and conditions of the GPL as |
20 | * it is applied to this Source Code. View the full text of the exception | 20 | * it is applied to this Source Code. View the full text of the exception |
21 | * in the file doc/FLOSS-exception.txt in this software distribution, or | 21 | * in the file doc/FLOSS-exception.txt in this software distribution, or |
22 | * online at http://secondlife.com/developers/opensource/flossexception | 22 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception |
23 | * | 23 | * |
24 | * By copying, modifying or distributing this software, you acknowledge | 24 | * By copying, modifying or distributing this software, you acknowledge |
25 | * that you have read and understood your obligations described above, | 25 | * that you have read and understood your obligations described above, |
@@ -34,6 +34,7 @@ | |||
34 | #include "linden_common.h" | 34 | #include "linden_common.h" |
35 | #include "llpumpio.h" | 35 | #include "llpumpio.h" |
36 | 36 | ||
37 | #include <map> | ||
37 | #include <set> | 38 | #include <set> |
38 | #include "apr-1/apr_poll.h" | 39 | #include "apr-1/apr_poll.h" |
39 | 40 | ||
@@ -41,10 +42,15 @@ | |||
41 | #include "llmemtype.h" | 42 | #include "llmemtype.h" |
42 | #include "llstl.h" | 43 | #include "llstl.h" |
43 | 44 | ||
44 | // This should not be in production, but it is intensely useful during | 45 | // These should not be enabled in production, but they can be |
45 | // development. | 46 | // intensely useful during development for finding certain kinds of |
47 | // bugs. | ||
46 | #if LL_LINUX | 48 | #if LL_LINUX |
47 | #define LL_DEBUG_PIPE_TYPE_IN_PUMP 0 | 49 | //#define LL_DEBUG_PIPE_TYPE_IN_PUMP 1 |
50 | //#define LL_DEBUG_POLL_FILE_DESCRIPTORS 1 | ||
51 | #if LL_DEBUG_POLL_FILE_DESCRIPTORS | ||
52 | #include "apr-1/apr_portable.h" | ||
53 | #endif | ||
48 | #endif | 54 | #endif |
49 | 55 | ||
50 | #if LL_DEBUG_PIPE_TYPE_IN_PUMP | 56 | #if LL_DEBUG_PIPE_TYPE_IN_PUMP |
@@ -73,6 +79,52 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS = 0.0f; | |||
73 | //#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN 1 | 79 | //#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN 1 |
74 | //#define LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT 1 | 80 | //#define LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT 1 |
75 | 81 | ||
82 | // | ||
83 | // local functions | ||
84 | // | ||
85 | void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll) | ||
86 | { | ||
87 | #if LL_DEBUG_POLL_FILE_DESCRIPTORS | ||
88 | if(!poll) | ||
89 | { | ||
90 | lldebugs << "Poll -- " << (msg?msg:"") << ": no pollfd." << llendl; | ||
91 | return; | ||
92 | } | ||
93 | if(poll->desc.s) | ||
94 | { | ||
95 | apr_os_sock_t os_sock; | ||
96 | if(APR_SUCCESS == apr_os_sock_get(&os_sock, poll->desc.s)) | ||
97 | { | ||
98 | lldebugs << "Poll -- " << (msg?msg:"") << " on fd " << os_sock | ||
99 | << " at " << poll->desc.s << llendl; | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | lldebugs << "Poll -- " << (msg?msg:"") << " no fd " | ||
104 | << " at " << poll->desc.s << llendl; | ||
105 | } | ||
106 | } | ||
107 | else if(poll->desc.f) | ||
108 | { | ||
109 | apr_os_file_t os_file; | ||
110 | if(APR_SUCCESS == apr_os_file_get(&os_file, poll->desc.f)) | ||
111 | { | ||
112 | lldebugs << "Poll -- " << (msg?msg:"") << " on fd " << os_file | ||
113 | << " at " << poll->desc.f << llendl; | ||
114 | } | ||
115 | else | ||
116 | { | ||
117 | lldebugs << "Poll -- " << (msg?msg:"") << " no fd " | ||
118 | << " at " << poll->desc.f << llendl; | ||
119 | } | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | lldebugs << "Poll -- " << (msg?msg:"") << ": no descriptor." << llendl; | ||
124 | } | ||
125 | #endif | ||
126 | } | ||
127 | |||
76 | /** | 128 | /** |
77 | * @class | 129 | * @class |
78 | */ | 130 | */ |
@@ -217,50 +269,88 @@ bool LLPumpIO::setTimeoutSeconds(F32 timeout) | |||
217 | return true; | 269 | return true; |
218 | } | 270 | } |
219 | 271 | ||
272 | static std::string events_2_string(apr_int16_t events) | ||
273 | { | ||
274 | std::ostringstream ostr; | ||
275 | if(events & APR_POLLIN) | ||
276 | { | ||
277 | ostr << "read,"; | ||
278 | } | ||
279 | if(events & APR_POLLPRI) | ||
280 | { | ||
281 | ostr << "priority,"; | ||
282 | } | ||
283 | if(events & APR_POLLOUT) | ||
284 | { | ||
285 | ostr << "write,"; | ||
286 | } | ||
287 | if(events & APR_POLLERR) | ||
288 | { | ||
289 | ostr << "error,"; | ||
290 | } | ||
291 | if(events & APR_POLLHUP) | ||
292 | { | ||
293 | ostr << "hangup,"; | ||
294 | } | ||
295 | if(events & APR_POLLNVAL) | ||
296 | { | ||
297 | ostr << "invalid,"; | ||
298 | } | ||
299 | return chop_tail_copy(ostr.str(), 1); | ||
300 | } | ||
301 | |||
220 | bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) | 302 | bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) |
221 | { | 303 | { |
222 | LLMemType m1(LLMemType::MTYPE_IO_PUMP); | 304 | LLMemType m1(LLMemType::MTYPE_IO_PUMP); |
223 | //lldebugs << "LLPumpIO::setConditional" << llendl; | 305 | if(!pipe) return false; |
224 | if(pipe) | 306 | ll_debug_poll_fd("Set conditional", poll); |
307 | |||
308 | lldebugs << "Setting conditionals (" << (poll ? events_2_string(poll->reqevents) :"null") | ||
309 | << ") " | ||
310 | #if LL_DEBUG_PIPE_TYPE_IN_PUMP | ||
311 | << "on pipe " << typeid(*pipe).name() | ||
312 | #endif | ||
313 | << " at " << pipe << llendl; | ||
314 | |||
315 | // remove any matching poll file descriptors for this pipe. | ||
316 | LLIOPipe::ptr_t pipe_ptr(pipe); | ||
317 | LLChainInfo::conditionals_t::iterator it; | ||
318 | it = (*mCurrentChain).mDescriptors.begin(); | ||
319 | while(it != (*mCurrentChain).mDescriptors.end()) | ||
225 | { | 320 | { |
226 | // remove any matching poll file descriptors for this pipe. | 321 | LLChainInfo::pipe_conditional_t& value = (*it); |
227 | LLIOPipe::ptr_t pipe_ptr(pipe); | 322 | if(pipe_ptr == value.first) |
228 | LLChainInfo::conditionals_t::iterator it; | ||
229 | it = (*mCurrentChain).mDescriptors.begin(); | ||
230 | while(it != (*mCurrentChain).mDescriptors.end()) | ||
231 | { | 323 | { |
232 | LLChainInfo::pipe_conditional_t& value = (*it); | 324 | ll_delete_apr_pollset_fd_client_data()(value); |
233 | if(pipe_ptr == value.first) | 325 | it = (*mCurrentChain).mDescriptors.erase(it); |
234 | { | 326 | mRebuildPollset = true; |
235 | ll_delete_apr_pollset_fd_client_data()(value); | ||
236 | it = (*mCurrentChain).mDescriptors.erase(it); | ||
237 | mRebuildPollset = true; | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | ++it; | ||
242 | } | ||
243 | } | 327 | } |
244 | 328 | else | |
245 | if(poll) | ||
246 | { | 329 | { |
247 | LLChainInfo::pipe_conditional_t value; | 330 | ++it; |
248 | value.first = pipe_ptr; | ||
249 | value.second = *poll; | ||
250 | if(!poll->p) | ||
251 | { | ||
252 | // each fd needs a pool to work with, so if one was | ||
253 | // not specified, use this pool. | ||
254 | // *FIX: Should it always be this pool? | ||
255 | value.second.p = mPool; | ||
256 | } | ||
257 | value.second.client_data = new S32(++mPollsetClientID); | ||
258 | (*mCurrentChain).mDescriptors.push_back(value); | ||
259 | mRebuildPollset = true; | ||
260 | } | 331 | } |
332 | } | ||
333 | |||
334 | if(!poll) | ||
335 | { | ||
336 | mRebuildPollset = true; | ||
261 | return true; | 337 | return true; |
262 | } | 338 | } |
263 | return false; | 339 | LLChainInfo::pipe_conditional_t value; |
340 | value.first = pipe_ptr; | ||
341 | value.second = *poll; | ||
342 | value.second.rtnevents = 0; | ||
343 | if(!poll->p) | ||
344 | { | ||
345 | // each fd needs a pool to work with, so if one was | ||
346 | // not specified, use this pool. | ||
347 | // *FIX: Should it always be this pool? | ||
348 | value.second.p = mPool; | ||
349 | } | ||
350 | value.second.client_data = new S32(++mPollsetClientID); | ||
351 | (*mCurrentChain).mDescriptors.push_back(value); | ||
352 | mRebuildPollset = true; | ||
353 | return true; | ||
264 | } | 354 | } |
265 | 355 | ||
266 | S32 LLPumpIO::setLock() | 356 | S32 LLPumpIO::setLock() |
@@ -412,24 +502,25 @@ void LLPumpIO::pump(const S32& poll_timeout) | |||
412 | } | 502 | } |
413 | 503 | ||
414 | // Poll based on the last known pollset | 504 | // Poll based on the last known pollset |
415 | // *FIX: may want to pass in a poll timeout so it works correctly | 505 | // *TODO: may want to pass in a poll timeout so it works correctly |
416 | // in single and multi threaded processes. | 506 | // in single and multi threaded processes. |
417 | PUMP_DEBUG; | 507 | PUMP_DEBUG; |
418 | typedef std::set<S32> signal_client_t; | 508 | typedef std::map<S32, S32> signal_client_t; |
419 | signal_client_t signalled_client; | 509 | signal_client_t signalled_client; |
510 | const apr_pollfd_t* poll_fd = NULL; | ||
420 | if(mPollset) | 511 | if(mPollset) |
421 | { | 512 | { |
422 | PUMP_DEBUG; | 513 | PUMP_DEBUG; |
423 | //llinfos << "polling" << llendl; | 514 | //llinfos << "polling" << llendl; |
424 | S32 count = 0; | 515 | S32 count = 0; |
425 | S32 client_id = 0; | 516 | S32 client_id = 0; |
426 | const apr_pollfd_t* poll_fd = NULL; | ||
427 | apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); | 517 | apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); |
428 | PUMP_DEBUG; | 518 | PUMP_DEBUG; |
429 | for(S32 i = 0; i < count; ++i) | 519 | for(S32 ii = 0; ii < count; ++ii) |
430 | { | 520 | { |
431 | client_id = *((S32*)poll_fd[i].client_data); | 521 | ll_debug_poll_fd("Signalled pipe", &poll_fd[ii]); |
432 | signalled_client.insert(client_id); | 522 | client_id = *((S32*)poll_fd[ii].client_data); |
523 | signalled_client[client_id] = ii; | ||
433 | } | 524 | } |
434 | PUMP_DEBUG; | 525 | PUMP_DEBUG; |
435 | } | 526 | } |
@@ -515,16 +606,51 @@ void LLPumpIO::pump(const S32& poll_timeout) | |||
515 | LLChainInfo::conditionals_t::iterator end; | 606 | LLChainInfo::conditionals_t::iterator end; |
516 | end = (*run_chain).mDescriptors.end(); | 607 | end = (*run_chain).mDescriptors.end(); |
517 | S32 client_id = 0; | 608 | S32 client_id = 0; |
609 | signal_client_t::iterator signal; | ||
518 | for(; it != end; ++it) | 610 | for(; it != end; ++it) |
519 | { | 611 | { |
520 | PUMP_DEBUG; | 612 | PUMP_DEBUG; |
521 | client_id = *((S32*)((*it).second.client_data)); | 613 | client_id = *((S32*)((*it).second.client_data)); |
522 | if(signalled_client.find(client_id) != not_signalled) | 614 | signal = signalled_client.find(client_id); |
615 | if (signal == not_signalled) continue; | ||
616 | static const apr_int16_t POLL_CHAIN_ERROR = | ||
617 | APR_POLLHUP | APR_POLLNVAL | APR_POLLERR; | ||
618 | const apr_pollfd_t* poll = &(poll_fd[(*signal).second]); | ||
619 | if(poll->rtnevents & POLL_CHAIN_ERROR) | ||
523 | { | 620 | { |
524 | process_this_chain = true; | 621 | // Potential eror condition has been |
622 | // returned. If HUP was one of them, we pass | ||
623 | // that as the error even though there may be | ||
624 | // more. If there are in fact more errors, | ||
625 | // we'll just wait for that detection until | ||
626 | // the next pump() cycle to catch it so that | ||
627 | // the logic here gets no more strained than | ||
628 | // it already is. | ||
629 | LLIOPipe::EStatus error_status; | ||
630 | if(poll->rtnevents & APR_POLLHUP) | ||
631 | error_status = LLIOPipe::STATUS_LOST_CONNECTION; | ||
632 | else | ||
633 | error_status = LLIOPipe::STATUS_ERROR; | ||
634 | if(handleChainError(*run_chain, error_status)) break; | ||
635 | ll_debug_poll_fd("Removing pipe", poll); | ||
636 | llwarns << "Removing pipe " | ||
637 | << (*run_chain).mChainLinks[0].mPipe | ||
638 | << " '" | ||
639 | #if LL_DEBUG_PIPE_TYPE_IN_PUMP | ||
640 | << typeid( | ||
641 | *((*run_chain).mChainLinks[0].mPipe)).name() | ||
642 | #endif | ||
643 | << "' because: " | ||
644 | << events_2_string(poll->rtnevents) | ||
645 | << llendl; | ||
646 | (*run_chain).mHead = (*run_chain).mChainLinks.end(); | ||
525 | break; | 647 | break; |
526 | } | 648 | } |
527 | //llinfos << "no fd ready for this one." << llendl; | 649 | |
650 | // at least 1 fd got signalled, and there were no | ||
651 | // errors. That means we process this chain. | ||
652 | process_this_chain = true; | ||
653 | break; | ||
528 | } | 654 | } |
529 | } | 655 | } |
530 | } | 656 | } |