XRootD
Loading...
Searching...
No Matches
XrdClPollerBuiltIn.cc
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// Copyright (c) 2011-2014 by European Organization for Nuclear Research (CERN)
3// Author: Lukasz Janyst <ljanyst@cern.ch>
4//------------------------------------------------------------------------------
5// This file is part of the XRootD software suite.
6//
7// XRootD is free software: you can redistribute it and/or modify
8// it under the terms of the GNU Lesser General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// XRootD is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU Lesser General Public License
18// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
19//
20// In applying this licence, CERN does not waive the privileges and immunities
21// granted to it by virtue of its status as an Intergovernmental Organization
22// or submit itself to any jurisdiction.
23//------------------------------------------------------------------------------
24
26#include "XrdCl/XrdClLog.hh"
29#include "XrdCl/XrdClSocket.hh"
31#include "XrdSys/XrdSysE2T.hh"
33
34namespace
35{
36 //----------------------------------------------------------------------------
37 // A helper struct passed to the callback as a custom arg
38 //----------------------------------------------------------------------------
39 struct PollerHelper
40 {
41 PollerHelper():
42 channel(0), callBack(0), readEnabled(false), writeEnabled(false),
43 readTimeout(0), writeTimeout(0)
44 {}
45 XrdSys::IOEvents::Channel *channel;
46 XrdSys::IOEvents::CallBack *callBack;
47 bool readEnabled;
48 bool writeEnabled;
49 time_t readTimeout;
50 time_t writeTimeout;
51 };
52
53 //----------------------------------------------------------------------------
54 // Call back implementation
55 //----------------------------------------------------------------------------
56 class SocketCallBack: public XrdSys::IOEvents::CallBack
57 {
58 public:
59 enum CallBackFlags
60 {
61 kRunningCallBack = 1,
62 kIdSet = 2,
63 kWantDisable = 4,
64 kDisabled = 8
65 };
66
67 struct DisableControl
68 {
69 DisableControl() : pFlags( 0 ), pCnd( 0 ) { }
70 ~DisableControl() { }
71
72 //------------------------------------------------------------------------
73 // Want to disable further callbacks. If callback is currently running
74 // in a different thread from our caller, wait until callback finishes.
75 //------------------------------------------------------------------------
76 void DisableCallBack()
77 {
78 const int flags = pFlags.fetch_or( kWantDisable );
79 if( !(flags & kIdSet) ) return;
80 if( !(flags & kRunningCallBack) ) return;
81 XrdSysCondVarHelper lck( pCnd );
82 if( XrdSysThread::Same( XrdSysThread::ID(), pSelfId ) ) return;
83 while( !(pFlags.load() & kDisabled) ) pCnd.Wait();
84 }
85
86 //--------------------------------------------------------------------
87 // In case the poller is started with existing SocketCallBacks (e.g.
88 // after a fork) we are called before reestablishing callbacks. We
89 // should reset flags, e.g. kIdSet so that pSelfId of new callback
90 // thread is recorded on the first of the new callbacks.
91 //--------------------------------------------------------------------
92 void Restart()
93 {
94 pFlags.fetch_and( ~kIdSet );
95 }
96
97 std::atomic<int> pFlags;
98 XrdSysCondVar pCnd;
99 pthread_t pSelfId;
100 };
101
102 SocketCallBack( XrdCl::Socket *sock, XrdCl::SocketHandler *sh ):
103 pSocket( sock ), pHandler( sh )
104 {
105 pControl = std::make_shared<DisableControl>();
106 }
107
108 virtual ~SocketCallBack() {};
109
110 virtual bool Event( XrdSys::IOEvents::Channel *chP,
111 void *cbArg,
112 int evFlags )
113 {
114 using namespace XrdCl;
115 uint8_t ev = 0;
116
117 if( evFlags & ReadyToRead ) ev |= SocketHandler::ReadyToRead;
118 if( evFlags & ReadTimeOut ) ev |= SocketHandler::ReadTimeOut;
119 if( evFlags & ReadyToWrite ) ev |= SocketHandler::ReadyToWrite;
120 if( evFlags & WriteTimeOut ) ev |= SocketHandler::WriteTimeOut;
121
122 Log *log = DefaultEnv::GetLog();
123 if( unlikely(log->GetLevel() >= Log::DumpMsg) )
124 {
125 log->Dump( PollerMsg, "%s Got an event: %s",
126 pSocket->GetName().c_str(),
127 SocketHandler::EventTypeToString( ev ).c_str() );
128 }
129
130 int flags = pControl->pFlags.fetch_or( kRunningCallBack );
131 if( !( flags & kIdSet ) )
132 {
133 XrdSysCondVarHelper lck( pControl->pCnd );
134 pControl->pSelfId = XrdSysThread::ID();
135 flags = pControl->pFlags.fetch_or( kIdSet );
136 }
137 if( flags & kWantDisable )
138 {
139 XrdSysCondVarHelper lck( pControl->pCnd );
140 pControl->pFlags &= ~kRunningCallBack;
141 pControl->pFlags |= kDisabled;
142 pControl->pCnd.Broadcast();
143 return false;
144 }
145
146 //----------------------------------------------------------------------
147 // If the event handler calls RemoveSocket for itself this object may
148 // be destroyed during the Event call.
149 //----------------------------------------------------------------------
150 auto control = pControl;
151 pHandler->Event( ev, pSocket );
152
153 flags = control->pFlags.fetch_and( ~kRunningCallBack );
154 if( flags & kWantDisable )
155 {
156 XrdSysCondVarHelper lck( control->pCnd );
157 control->pFlags |= kDisabled;
158 control->pCnd.Broadcast();
159 return false;
160 }
161 return true;
162 }
163
164 std::shared_ptr<DisableControl> GetControl()
165 {
166 return pControl;
167 }
168
169 private:
170 XrdCl::Socket *pSocket;
171 XrdCl::SocketHandler *pHandler;
172 std::shared_ptr<DisableControl> pControl;
173 };
174}
175
176
177namespace XrdCl
178{
179 //----------------------------------------------------------------------------
180 // Initialize the poller
181 //----------------------------------------------------------------------------
183 {
184 return true;
185 }
186
187 //----------------------------------------------------------------------------
188 // Finalize the poller
189 //----------------------------------------------------------------------------
191 {
192 //--------------------------------------------------------------------------
193 // Clean up the channels
194 //--------------------------------------------------------------------------
195 SocketMap::iterator it;
196 for( it = pSocketMap.begin(); it != pSocketMap.end(); ++it )
197 {
198 PollerHelper *helper = (PollerHelper*)it->second;
199 if( helper->channel ) helper->channel->Delete();
200 delete helper->callBack;
201 delete helper;
202 }
203 pSocketMap.clear();
204
205 return true;
206 }
207
208 //------------------------------------------------------------------------
209 // Start polling
210 //------------------------------------------------------------------------
212 {
213 //--------------------------------------------------------------------------
214 // Start the poller
215 //--------------------------------------------------------------------------
216 using namespace XrdSys;
217
218 Log *log = DefaultEnv::GetLog();
219 log->Debug( PollerMsg, "Creating and starting the built-in poller..." );
220 XrdSysMutexHelper scopedLock( pMutex );
221 int errNum = 0;
222 const char *errMsg = 0;
223
224 for( int i = 0; i < pNbPoller; ++i )
225 {
226 XrdSys::IOEvents::Poller* poller = IOEvents::Poller::Create( errNum, &errMsg );
227 if( !poller )
228 {
229 log->Error( PollerMsg, "Unable to create the internal poller object: "
230 "%s (%s)", XrdSysE2T( errno ), errMsg );
231 return false;
232 }
233 pPollerPool.push_back( poller );
234 }
235
236 pNext = pPollerPool.begin();
237
238 log->Debug( PollerMsg, "Using %d poller threads", pNbPoller );
239
240 //--------------------------------------------------------------------------
241 // Check if we have any descriptors to reinsert from the last time we
242 // were started
243 //--------------------------------------------------------------------------
244 SocketMap::iterator it;
245 for( it = pSocketMap.begin(); it != pSocketMap.end(); ++it )
246 {
247 PollerHelper *helper = (PollerHelper*)it->second;
248 Socket *socket = it->first;
249
250 // static cast for the downcast as we're sure it's a SocketCallBack
251 auto *scb = static_cast<SocketCallBack*>( helper->callBack );
252 if( scb )
253 {
254 auto dc = scb->GetControl();
255 if( dc ) dc->Restart();
256 }
257
258 helper->channel = new IOEvents::Channel( RegisterAndGetPoller( socket ), socket->GetFD(),
259 helper->callBack );
260 if( helper->readEnabled )
261 {
262 bool status = helper->channel->Enable( IOEvents::Channel::readEvents,
263 helper->readTimeout, &errMsg );
264 if( !status )
265 {
266 log->Error( PollerMsg, "Unable to enable read notifications "
267 "while re-starting %s (%s)", XrdSysE2T( errno ), errMsg );
268
269 return false;
270 }
271 }
272
273 if( helper->writeEnabled )
274 {
275 bool status = helper->channel->Enable( IOEvents::Channel::writeEvents,
276 helper->writeTimeout, &errMsg );
277 if( !status )
278 {
279 log->Error( PollerMsg, "Unable to enable write notifications "
280 "while re-starting %s (%s)", XrdSysE2T( errno ), errMsg );
281
282 return false;
283 }
284 }
285 }
286 return true;
287 }
288
289 //------------------------------------------------------------------------
290 // Stop polling
291 //------------------------------------------------------------------------
293 {
294 using namespace XrdSys::IOEvents;
295
296 Log *log = DefaultEnv::GetLog();
297 log->Debug( PollerMsg, "Stopping the poller..." );
298
299 XrdSysMutexHelper scopedLock( pMutex );
300
301 if( pPollerPool.empty() )
302 {
303 log->Debug( PollerMsg, "Stopping a poller that has not been started" );
304 return true;
305 }
306
307 while( !pPollerPool.empty() )
308 {
309 XrdSys::IOEvents::Poller *poller = pPollerPool.back();
310 if( *pNext == poller )
311 pNext = pPollerPool.begin();
312 pPollerPool.pop_back();
313
314 if( !poller ) continue;
315
316 scopedLock.UnLock();
317 poller->Stop();
318 delete poller;
319 scopedLock.Lock( &pMutex );
320 }
321 pNext = pPollerPool.end();
322 pPollerMap.clear();
323
324 SocketMap::iterator it;
325 const char *errMsg = 0;
326
327 for( it = pSocketMap.begin(); it != pSocketMap.end(); ++it )
328 {
329 PollerHelper *helper = (PollerHelper*)it->second;
330 if( !helper->channel ) continue;
331 bool status = helper->channel->Disable( Channel::allEvents, &errMsg );
332 if( !status )
333 {
334 Socket *socket = it->first;
335 log->Error( PollerMsg, "%s Unable to disable write notifications: %s",
336 socket->GetName().c_str(), errMsg );
337 }
338 helper->channel->Delete();
339 helper->channel = 0;
340 }
341
342 return true;
343 }
344
345 //------------------------------------------------------------------------
346 // Add socket to the polling queue
347 //------------------------------------------------------------------------
349 SocketHandler *handler )
350 {
351 Log *log = DefaultEnv::GetLog();
352 XrdSysMutexHelper scopedLock( pMutex );
353
354 if( !socket )
355 {
356 log->Error( PollerMsg, "Invalid socket, impossible to poll" );
357 return false;
358 }
359
360 if( socket->GetStatus() != Socket::Connected &&
361 socket->GetStatus() != Socket::Connecting )
362 {
363 log->Error( PollerMsg, "Socket is not in a state valid for polling" );
364 return false;
365 }
366
367 log->Debug( PollerMsg, "Adding socket %p to the poller", (void*)socket );
368
369 //--------------------------------------------------------------------------
370 // Check if the socket is already registered
371 //--------------------------------------------------------------------------
372 SocketMap::const_iterator it = pSocketMap.find( socket );
373 if( it != pSocketMap.end() )
374 {
375 log->Warning( PollerMsg, "%s Already registered with this poller",
376 socket->GetName().c_str() );
377 return false;
378 }
379
380 //--------------------------------------------------------------------------
381 // Create the socket helper
382 //--------------------------------------------------------------------------
383 XrdSys::IOEvents::Poller* poller = RegisterAndGetPoller( socket );
384
385 if( !poller )
386 {
387 log->Error( PollerMsg, "No poller available, can not add socket" );
388 return false;
389 }
390
391 PollerHelper *helper = new PollerHelper();
392 helper->callBack = new ::SocketCallBack( socket, handler );
393
394 if( poller )
395 {
396 helper->channel = new XrdSys::IOEvents::Channel( poller,
397 socket->GetFD(),
398 helper->callBack );
399 }
400
401 handler->Initialize( this );
402 pSocketMap[socket] = helper;
403 return true;
404 }
405
406 //----------------------------------------------------------------------------
407 // This disables further callbacks to the socket's handler from the poller
408 // thread. Will wait until any current callback completes (unless our caller
409 // is the same thread). We do not yet remove the socket from the poller.
410 // Removal may still block until the relevant poller thread can run.
411 //----------------------------------------------------------------------------
413 {
414 XrdSysMutexHelper scopedLock( pMutex );
415 SocketMap::iterator it = pSocketMap.find( socket );
416 if( it == pSocketMap.end() )
417 return;
418
419 PollerHelper *helper = (PollerHelper*)it->second;
420 if( !helper ) return;
421 XrdSys::IOEvents::CallBack *cb = helper->callBack;
422 if( !cb ) return;
423 SocketCallBack *scb = dynamic_cast<SocketCallBack*>( cb );
424 if( !scb ) return;
425 auto dc = scb->GetControl();
426 scopedLock.UnLock();
427 dc->DisableCallBack();
428 }
429
430 //------------------------------------------------------------------------
431 // Remove the socket
432 //------------------------------------------------------------------------
434 {
435 using namespace XrdSys::IOEvents;
436 Log *log = DefaultEnv::GetLog();
437
438 //--------------------------------------------------------------------------
439 // Find the right socket
440 //--------------------------------------------------------------------------
441 XrdSysMutexHelper scopedLock( pMutex );
442 SocketMap::iterator it = pSocketMap.find( socket );
443 if( it == pSocketMap.end() )
444 return true;
445
446 log->Debug( PollerMsg, "%s Removing socket from the poller",
447 socket->GetName().c_str() );
448
449 // unregister from the poller it's currently associated with
450 UnregisterFromPoller( socket );
451
452 //--------------------------------------------------------------------------
453 // Remove the socket
454 //--------------------------------------------------------------------------
455 PollerHelper *helper = (PollerHelper*)it->second;
456 pSocketMap.erase( it );
457 scopedLock.UnLock();
458
459 if( helper->channel )
460 {
461 const char *errMsg;
462 bool status = helper->channel->Disable( Channel::allEvents, &errMsg );
463 if( !status )
464 {
465 log->Error( PollerMsg, "%s Unable to disable write notifications: %s",
466 socket->GetName().c_str(), errMsg );
467 return false;
468 }
469 helper->channel->Delete();
470 }
471 delete helper->callBack;
472 delete helper;
473 return true;
474 }
475
476 //----------------------------------------------------------------------------
477 // Notify the handler about read events
478 //----------------------------------------------------------------------------
480 bool notify,
481 time_t timeout )
482 {
483 using namespace XrdSys::IOEvents;
484 Log *log = DefaultEnv::GetLog();
485
486 if( !socket )
487 {
488 log->Error( PollerMsg, "Invalid socket, read events unavailable" );
489 return false;
490 }
491
492 //--------------------------------------------------------------------------
493 // Check if the socket is registered
494 //--------------------------------------------------------------------------
495 XrdSysMutexHelper scopedLock( pMutex );
496 SocketMap::const_iterator it = pSocketMap.find( socket );
497 if( it == pSocketMap.end() )
498 {
499 log->Warning( PollerMsg, "%s Socket is not registered",
500 socket->GetName().c_str() );
501 return false;
502 }
503
504 PollerHelper *helper = (PollerHelper*)it->second;
505 XrdSys::IOEvents::Poller *poller = GetPoller( socket );
506
507 //--------------------------------------------------------------------------
508 // Enable read notifications
509 //--------------------------------------------------------------------------
510 if( notify )
511 {
512 if( helper->readEnabled )
513 return true;
514 helper->readTimeout = timeout;
515
516 log->Dump( PollerMsg, "%s Enable read notifications, timeout: %lld",
517 socket->GetName().c_str(), (long long)timeout );
518
519 if( poller )
520 {
521 const char *errMsg;
522 bool status = helper->channel->Enable( Channel::readEvents, timeout,
523 &errMsg );
524 if( !status )
525 {
526 log->Error( PollerMsg, "%s Unable to enable read notifications: %s",
527 socket->GetName().c_str(), errMsg );
528 return false;
529 }
530 }
531 helper->readEnabled = true;
532 }
533
534 //--------------------------------------------------------------------------
535 // Disable read notifications
536 //--------------------------------------------------------------------------
537 else
538 {
539 if( !helper->readEnabled )
540 return true;
541
542 log->Dump( PollerMsg, "%s Disable read notifications",
543 socket->GetName().c_str() );
544
545 if( poller )
546 {
547 const char *errMsg;
548 bool status = helper->channel->Disable( Channel::readEvents, &errMsg );
549 if( !status )
550 {
551 log->Error( PollerMsg, "%s Unable to disable read notifications: %s",
552 socket->GetName().c_str(), errMsg );
553 return false;
554 }
555 }
556 helper->readEnabled = false;
557 }
558 return true;
559 }
560
561 //----------------------------------------------------------------------------
562 // Notify the handler about write events
563 //----------------------------------------------------------------------------
565 bool notify,
566 time_t timeout )
567 {
568 using namespace XrdSys::IOEvents;
569 Log *log = DefaultEnv::GetLog();
570
571 if( !socket )
572 {
573 log->Error( PollerMsg, "Invalid socket, write events unavailable" );
574 return false;
575 }
576
577 //--------------------------------------------------------------------------
578 // Check if the socket is registered
579 //--------------------------------------------------------------------------
580 XrdSysMutexHelper scopedLock( pMutex );
581 SocketMap::const_iterator it = pSocketMap.find( socket );
582 if( it == pSocketMap.end() )
583 {
584 log->Warning( PollerMsg, "%s Socket is not registered",
585 socket->GetName().c_str() );
586 return false;
587 }
588
589 PollerHelper *helper = (PollerHelper*)it->second;
590 XrdSys::IOEvents::Poller *poller = GetPoller( socket );
591
592 //--------------------------------------------------------------------------
593 // Enable write notifications
594 //--------------------------------------------------------------------------
595 if( notify )
596 {
597 if( helper->writeEnabled )
598 return true;
599
600 helper->writeTimeout = timeout;
601
602 log->Dump( PollerMsg, "%s Enable write notifications, timeout: %lld",
603 socket->GetName().c_str(), (long long)timeout );
604
605 if( poller )
606 {
607 const char *errMsg;
608 bool status = helper->channel->Enable( Channel::writeEvents, timeout,
609 &errMsg );
610 if( !status )
611 {
612 log->Error( PollerMsg, "%s Unable to enable write notifications: %s",
613 socket->GetName().c_str(), errMsg );
614 return false;
615 }
616 }
617 helper->writeEnabled = true;
618 }
619
620 //--------------------------------------------------------------------------
621 // Disable read notifications
622 //--------------------------------------------------------------------------
623 else
624 {
625 if( !helper->writeEnabled )
626 return true;
627
628 log->Dump( PollerMsg, "%s Disable write notifications",
629 socket->GetName().c_str() );
630 if( poller )
631 {
632 const char *errMsg;
633 bool status = helper->channel->Disable( Channel::writeEvents, &errMsg );
634 if( !status )
635 {
636 log->Error( PollerMsg, "%s Unable to disable write notifications: %s",
637 socket->GetName().c_str(), errMsg );
638 return false;
639 }
640 }
641 helper->writeEnabled = false;
642 }
643 return true;
644 }
645
646 //----------------------------------------------------------------------------
647 // Check whether the socket is registered with the poller
648 //----------------------------------------------------------------------------
650 {
651 XrdSysMutexHelper scopedLock( pMutex );
652 SocketMap::iterator it = pSocketMap.find( socket );
653 return it != pSocketMap.end();
654 }
655
656 //----------------------------------------------------------------------------
657 // Return poller threads in round-robin fashion
658 //----------------------------------------------------------------------------
659 XrdSys::IOEvents::Poller* PollerBuiltIn::GetNextPoller()
660 {
661 if( pPollerPool.empty() ) return 0;
662
663 PollerPool::iterator ret = pNext;
664 ++pNext;
665 if( pNext == pPollerPool.end() )
666 pNext = pPollerPool.begin();
667 return *ret;
668 }
669
670 //----------------------------------------------------------------------------
671 // Return the poller associated with the respective channel
672 //----------------------------------------------------------------------------
673 XrdSys::IOEvents::Poller* PollerBuiltIn::RegisterAndGetPoller(const Socket * socket)
674 {
675 PollerMap::iterator itr = pPollerMap.find( socket->GetFD() );
676
677 if( itr == pPollerMap.end() )
678 {
679 XrdSys::IOEvents::Poller* poller = GetNextPoller();
680 if( poller )
681 pPollerMap[socket->GetFD()] = poller;
682 return poller;
683 }
684
685 return itr->second;
686 }
687
688 void PollerBuiltIn::UnregisterFromPoller( const Socket *socket )
689 {
690 PollerMap::iterator itr = pPollerMap.find( socket->GetFD() );
691 if( itr == pPollerMap.end() ) return;
692 pPollerMap.erase( itr );
693 }
694
695 XrdSys::IOEvents::Poller* PollerBuiltIn::GetPoller(const Socket * socket)
696 {
697 PollerMap::iterator itr = pPollerMap.find( socket->GetFD() );
698 if( itr == pPollerMap.end() ) return 0;
699 return itr->second;
700 }
701
702 //----------------------------------------------------------------------------
703 // Get the initial value for pNbPoller
704 //----------------------------------------------------------------------------
705 int PollerBuiltIn::GetNbPollerInit()
706 {
707 Env * env = DefaultEnv::GetEnv();
709 env->GetInt("ParallelEvtLoop", ret);
710 return ret;
711 }
712}
#define unlikely(x)
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
static Log * GetLog()
Get default log.
static Env * GetEnv()
Get default client environment.
bool GetInt(const std::string &key, int &value)
Definition XrdClEnv.cc:115
Handle diagnostics.
Definition XrdClLog.hh:101
void Error(uint64_t topic, const char *format,...)
Report an error.
Definition XrdClLog.cc:231
LogLevel GetLevel() const
Get the log level.
Definition XrdClLog.hh:258
void Warning(uint64_t topic, const char *format,...)
Report a warning.
Definition XrdClLog.cc:248
void Dump(uint64_t topic, const char *format,...)
Print a dump message.
Definition XrdClLog.cc:299
void Debug(uint64_t topic, const char *format,...)
Print a debug message.
Definition XrdClLog.cc:282
virtual bool AddSocket(Socket *socket, SocketHandler *handler)
virtual bool EnableReadNotification(Socket *socket, bool notify, time_t timeout=60)
virtual bool RemoveSocket(Socket *socket)
Remove the socket.
virtual bool Stop()
Stop polling.
virtual void ShutdownEvents(Socket *socket)
virtual bool EnableWriteNotification(Socket *socket, bool notify, time_t timeout=60)
virtual bool IsRegistered(Socket *socket)
Check whether the socket is registered with the poller.
virtual bool Finalize()
Finalize the poller.
virtual bool Initialize()
Initialize the poller.
virtual bool Start()
Start polling.
virtual void Initialize(Poller *)
Initializer.
A network socket.
std::string GetName() const
Get the string representation of the socket.
@ Connected
The socket is connected.
@ Connecting
The connection process is in progress.
int GetFD() const
Get the file descriptor.
SocketStatus GetStatus() const
Get the socket status.
void Lock(XrdSysMutex *Mutex)
static int Same(pthread_t t1, pthread_t t2)
static pthread_t ID(void)
@ allEvents
All of the above.
@ writeEvents
Write and Write Timeouts.
@ readEvents
Read and Read Timeouts.
bool Enable(int events, int timeout=0, const char **eText=0)
bool Disable(int events, const char **eText=0)
static Poller * Create(int &eNum, const char **eTxt=0, int crOpts=0)
const uint64_t PollerMsg
const int DefaultParallelEvtLoop
XrdSysError Log
Definition XrdConfig.cc:113