aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage/llpumpio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llmessage/llpumpio.cpp')
-rw-r--r--linden/indra/llmessage/llpumpio.cpp222
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//
85void 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
272static 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
220bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll) 302bool 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
266S32 LLPumpIO::setLock() 356S32 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 }